├── icamera ├── proguard-rules.pro ├── .gitignore ├── src │ └── main │ │ ├── res │ │ ├── values │ │ │ ├── strings.xml │ │ │ ├── styles.xml │ │ │ └── attrs.xml │ │ ├── drawable │ │ │ ├── ic_focus_marker_fill.xml │ │ │ └── ic_focus_marker_outline.xml │ │ └── layout │ │ │ └── layout_focus_marker.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── me │ │ └── shouheng │ │ └── icamera │ │ ├── listener │ │ ├── OnOrientationChangedListener.kt │ │ ├── CameraCloseListener.kt │ │ ├── CameraPhotoListener.kt │ │ ├── OnMoveListener.kt │ │ ├── CameraVideoListener.kt │ │ ├── CameraOpenListener.kt │ │ ├── CameraSizeListener.kt │ │ ├── CameraPreviewListener.kt │ │ └── DisplayOrientationDetector.kt │ │ ├── config │ │ ├── size │ │ │ ├── SizeMap.kt │ │ │ ├── AspectRatio.kt │ │ │ └── Size.kt │ │ ├── convert │ │ │ ├── ImageRawDataConverter.kt │ │ │ └── ImageRawDataConverterImpl.kt │ │ ├── creator │ │ │ ├── impl │ │ │ │ ├── SurfaceViewOnlyCreator.kt │ │ │ │ ├── TextureViewOnlyCreator.kt │ │ │ │ ├── Camera1OnlyCreator.kt │ │ │ │ ├── Camera2OnlyCreator.kt │ │ │ │ ├── CameraPreviewCreatorImpl.kt │ │ │ │ └── CameraManagerCreatorImpl.kt │ │ │ ├── CameraManagerCreator.kt │ │ │ └── CameraPreviewCreator.kt │ │ └── calculator │ │ │ ├── CameraSizeCalculator.kt │ │ │ └── impl │ │ │ └── CameraSizeCalculatorImpl.kt │ │ ├── preview │ │ ├── CameraPreviewCallback.kt │ │ ├── impl │ │ │ ├── BaseCameraPreview.kt │ │ │ ├── TexturePreview.kt │ │ │ └── SurfacePreview.kt │ │ └── CameraPreview.kt │ │ ├── enums │ │ ├── MediaType.kt │ │ ├── CameraFace.kt │ │ ├── DeviceDefaultOrientation.kt │ │ ├── CameraType.kt │ │ ├── FlashMode.kt │ │ ├── PreviewViewType.kt │ │ ├── CameraSizeFor.kt │ │ ├── SensorPosition.kt │ │ ├── MediaQuality.kt │ │ └── PreviewAdjustType.kt │ │ ├── util │ │ ├── XUtils.kt │ │ ├── XLog.kt │ │ └── ImageHelper.kt │ │ └── manager │ │ └── CameraManager.kt └── build.gradle ├── sample ├── app │ ├── .gitignore │ ├── proguard-rules.pro │ ├── src │ │ └── main │ │ │ ├── res │ │ │ ├── raw │ │ │ │ ├── tex00.jpg │ │ │ │ ├── tex07.jpg │ │ │ │ ├── tex11.png │ │ │ │ ├── original.fsh │ │ │ │ ├── vertext.vsh │ │ │ │ ├── original_rtt.fsh │ │ │ │ ├── pixelize.fsh │ │ │ │ ├── negative.fsh │ │ │ │ ├── gray.fsh │ │ │ │ ├── basic_deform.fsh │ │ │ │ ├── black_and_white.fsh │ │ │ │ ├── casting.fsh │ │ │ │ ├── edge_detection.fsh │ │ │ │ ├── nostalgia.fsh │ │ │ │ ├── mirror.fsh │ │ │ │ ├── blue_orange.fsh │ │ │ │ ├── cartoon.fsh │ │ │ │ ├── refraction.fsh │ │ │ │ ├── triple.fsh │ │ │ │ ├── water_reflection.fsh │ │ │ │ ├── triangles_mosaic.fsh │ │ │ │ ├── mapping.fsh │ │ │ │ ├── relief.fsh │ │ │ │ ├── contrast.fsh │ │ │ │ ├── voronoi_buf_c.fsh │ │ │ │ ├── chromatic_aberration.fsh │ │ │ │ ├── legofied.fsh │ │ │ │ ├── lichtenstein_esque.fsh │ │ │ │ ├── voronoi.fsh │ │ │ │ ├── swirl.fsh │ │ │ │ ├── em_interference.fsh │ │ │ │ ├── noise_warp.fsh │ │ │ │ ├── cracked.fsh │ │ │ │ ├── voronoi_buf_a.fsh │ │ │ │ ├── tile_mosaic.fsh │ │ │ │ ├── polygonization.fsh │ │ │ │ ├── hexagon_mosaic.fsh │ │ │ │ ├── voronoi_buf_b.fsh │ │ │ │ ├── money_filter.fsh │ │ │ │ └── crosshatch.fsh │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── xml │ │ │ │ └── provider_paths.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── values │ │ │ │ ├── colors.xml │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ ├── drawable │ │ │ │ ├── ic_flash_on_white_24dp.xml │ │ │ │ ├── ic_flash_off_white_24dp.xml │ │ │ │ ├── ic_flash_auto_white_24dp.xml │ │ │ │ ├── ic_videocam_white_24dp.xml │ │ │ │ ├── ic_photo_camera_white_24dp.xml │ │ │ │ ├── ic_circle_white.xml │ │ │ │ ├── ic_party_mode_white_24dp.xml │ │ │ │ └── ic_settings_white_24dp.xml │ │ │ ├── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ │ └── menu │ │ │ │ └── filter.xml │ │ │ ├── ic_launcher-web.png │ │ │ ├── java │ │ │ └── me │ │ │ │ └── shouheng │ │ │ │ └── icamerasample │ │ │ │ ├── filter │ │ │ │ ├── GrayFilter.java │ │ │ │ ├── SwirlFilter.java │ │ │ │ ├── MirrorFilter.java │ │ │ │ ├── ReliefFilter.java │ │ │ │ ├── CartoonFilter.java │ │ │ │ ├── CastingFilter.java │ │ │ │ ├── NegativeFilter.java │ │ │ │ ├── TripleFilter.java │ │ │ │ ├── NostalgiaFilter.java │ │ │ │ ├── BlackAndWhiteFilter.java │ │ │ │ ├── HexagonMosaicFilter.java │ │ │ │ ├── WaterReflectionFilter.java │ │ │ │ ├── CrackedFilter.java │ │ │ │ ├── MoneyFilter.java │ │ │ │ ├── AsciiArtFilter.java │ │ │ │ ├── ContrastFilter.java │ │ │ │ ├── PixelizeFilter.java │ │ │ │ ├── BlueorangeFilter.java │ │ │ │ ├── CrosshatchFilter.java │ │ │ │ ├── NoiseWarpFilter.java │ │ │ │ ├── OriginalFilter.java │ │ │ │ ├── TileMosaicFilter.java │ │ │ │ ├── BasicDeformFilter.java │ │ │ │ ├── LegofiedFilter.java │ │ │ │ ├── EdgeDetectionFilter.java │ │ │ │ ├── PolygonizationFilter.java │ │ │ │ ├── EMInterferenceFilter.java │ │ │ │ ├── LichtensteinEsqueFilter.java │ │ │ │ ├── TrianglesMosaicFilter.java │ │ │ │ ├── ChromaticAberrationFilter.java │ │ │ │ ├── MappingFilter.java │ │ │ │ ├── RefractionFilter.java │ │ │ │ └── JFAVoronoiFilter.java │ │ │ │ ├── utils │ │ │ │ └── FileHelper.kt │ │ │ │ ├── render │ │ │ │ └── RenderBuffer.java │ │ │ │ ├── App.kt │ │ │ │ └── activity │ │ │ │ └── MainActivity.kt │ │ │ └── AndroidManifest.xml │ └── build.gradle ├── sample.apk ├── icamera.jks ├── settings.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradle.properties ├── .idea │ ├── codeStyles │ │ ├── codeStyleConfig.xml │ │ └── Project.xml │ ├── compiler.xml │ ├── vcs.xml │ ├── misc.xml │ ├── runConfigurations.xml │ ├── gradle.xml │ ├── inspectionProfiles │ │ └── Project_Default.xml │ └── jarRepositories.xml ├── .gitignore ├── build.gradle └── gradlew.bat ├── CHANGELOG.md ├── images ├── ali.jpg ├── mm.png └── design.png ├── .travis.yml └── TESTLIST.md /icamera/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /icamera/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.0.1-beta 2 | 3 | - first release 4 | 5 | 6 | -------------------------------------------------------------------------------- /images/ali.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/images/ali.jpg -------------------------------------------------------------------------------- /images/mm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/images/mm.png -------------------------------------------------------------------------------- /images/design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/images/design.png -------------------------------------------------------------------------------- /sample/sample.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/sample/sample.apk -------------------------------------------------------------------------------- /sample/icamera.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/sample/icamera.jks -------------------------------------------------------------------------------- /sample/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':icamera' 2 | project(':icamera').projectDir = new File('../icamera') -------------------------------------------------------------------------------- /icamera/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | CameraX 3 | 4 | -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/tex00.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/sample/app/src/main/res/raw/tex00.jpg -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/tex07.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/sample/app/src/main/res/raw/tex07.jpg -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/tex11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/sample/app/src/main/res/raw/tex11.png -------------------------------------------------------------------------------- /sample/app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/sample/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /sample/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/sample/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /icamera/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /sample/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/sample/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/sample/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/sample/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/sample/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/sample/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sample/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/sample/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sample/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/sample/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sample/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/sample/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sample/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/sample/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /sample/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/sample/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sample/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/sample/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /sample/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/sample/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shouheng88/iCamera/HEAD/sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /sample/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536m 2 | kotlin.code.style=official 3 | 4 | _keyAlias=key0 5 | _keyPassword=123456 6 | _storeFile=../icamera.jks 7 | _storePassword=123456 8 | -------------------------------------------------------------------------------- /sample/.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /sample/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /sample/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /sample/app/src/main/res/xml/provider_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/original.fsh: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | 3 | varying vec2 texCoord; 4 | uniform sampler2D iChannel0; 5 | 6 | void main() { 7 | gl_FragColor = texture2D(iChannel0, texCoord); 8 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/vertext.vsh: -------------------------------------------------------------------------------- 1 | attribute vec2 vPosition; 2 | attribute vec2 vTexCoord; 3 | varying vec2 texCoord; 4 | 5 | void main() { 6 | texCoord = vTexCoord; 7 | gl_Position = vec4 ( vPosition.x, vPosition.y, 0.0, 1.0 ); 8 | } -------------------------------------------------------------------------------- /icamera/src/main/res/drawable/ic_focus_marker_fill.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /sample/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches/build_file_checksums.ser 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/gradle.xml 9 | .DS_Store 10 | /build 11 | /captures 12 | .externalNativeBuild 13 | gradle.properties -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/original_rtt.fsh: -------------------------------------------------------------------------------- 1 | #extension GL_OES_EGL_image_external : require 2 | precision mediump float; 3 | 4 | varying vec2 texCoord; 5 | uniform samplerExternalOES iChannel0; 6 | 7 | void main() { 8 | gl_FragColor = texture2D(iChannel0, texCoord); 9 | } -------------------------------------------------------------------------------- /icamera/src/main/res/drawable/ic_focus_marker_outline.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/listener/OnOrientationChangedListener.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.listener 2 | 3 | /** 4 | * @author [WngShhng](mailto:shouheng2015@gmail.com) 5 | * @version 2020-08-27 10:26 6 | */ 7 | interface OnOrientationChangedListener { 8 | fun onOrientationChanged(degree: Int) 9 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /sample/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/config/size/SizeMap.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.config.size 2 | 3 | import java.util.* 4 | 5 | /** 6 | * Size map from aspect ration to sizes 7 | * 8 | * @author WngShhng (shouheng2015@gmail.com) 9 | * @version 2019/4/16 22:57 10 | */ 11 | class SizeMap : HashMap>() 12 | -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/listener/CameraCloseListener.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.listener 2 | 3 | import me.shouheng.icamera.enums.CameraFace 4 | 5 | /** 6 | * @author WngShhng (shouheng2015@gmail.com) 7 | * @version 2019/4/17 22:47 8 | */ 9 | interface CameraCloseListener { 10 | fun onCameraClosed(@CameraFace cameraFace: Int) 11 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #111111 4 | #111111 5 | #1F1F1F 6 | #185CFF 7 | #1C0000 8 | 9 | -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/listener/CameraPhotoListener.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.listener 2 | 3 | import java.io.File 4 | 5 | /** 6 | * @author WngShhng (shouheng2015@gmail.com) 7 | * @version 2019/4/14 14:30 8 | */ 9 | interface CameraPhotoListener { 10 | fun onPictureTaken(data: ByteArray, picture: File) 11 | fun onCaptureFailed(throwable: Throwable) 12 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/listener/OnMoveListener.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.listener 2 | 3 | /** 4 | * The finger move event listener on the focus maker. 5 | * You can add this callback to listen the event. 6 | * 7 | * @author WngShhng (shouheng2015@gmail.com) 8 | * @version 2019/4/15 8:31 9 | */ 10 | interface OnMoveListener { 11 | fun onMove(left: Boolean) 12 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/listener/CameraVideoListener.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.listener 2 | 3 | import java.io.File 4 | 5 | /** 6 | * @author WngShhng (shouheng2015@gmail.com) 7 | * @version 2019/4/14 19:49 8 | */ 9 | interface CameraVideoListener { 10 | fun onVideoRecordStart() 11 | fun onVideoRecordStop(file: File) 12 | fun onVideoRecordError(throwable: Throwable) 13 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/drawable/ic_flash_on_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/listener/CameraOpenListener.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.listener 2 | 3 | import me.shouheng.icamera.enums.CameraFace 4 | 5 | /** 6 | * @author WngShhng (shouheng2015@gmail.com) 7 | * @version 2019/4/14 10:40 8 | */ 9 | interface CameraOpenListener { 10 | fun onCameraOpened(@CameraFace cameraFace: Int) 11 | fun onCameraOpenError(throwable: Throwable) 12 | } -------------------------------------------------------------------------------- /sample/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | jdk: oraclejdk8 3 | sudo: false 4 | android: 5 | components: 6 | - tools 7 | - tools 8 | - build-tools-28.0.0 9 | - android-28 10 | - extra-google-m2repository 11 | - extra-android-m2repository 12 | licenses: 13 | - android-sdk-preview-license-.+ 14 | - android-sdk-license-.+ 15 | - google-gdk-license-.+ 16 | script: ./sample/gradlew build 17 | -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/listener/CameraSizeListener.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.listener 2 | 3 | import me.shouheng.icamera.config.size.Size 4 | 5 | /** 6 | * @author WngShhng (shouheng2015@gmail.com) 7 | * @version 2019/4/16 22:46 8 | */ 9 | interface CameraSizeListener { 10 | fun onPreviewSizeUpdated(previewSize: Size) 11 | fun onVideoSizeUpdated(videoSize: Size) 12 | fun onPictureSizeUpdated(pictureSize: Size) 13 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/pixelize.fsh: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | 3 | uniform vec3 iResolution; 4 | uniform sampler2D iChannel0; 5 | varying vec2 texCoord; 6 | 7 | #define S (iResolution.x / 6e1) // The cell size. 8 | 9 | void mainImage(out vec4 c, vec2 p) 10 | { 11 | c = texture2D(iChannel0, floor((p + .5) / S) * S / iResolution.xy); 12 | } 13 | 14 | void main() { 15 | mainImage(gl_FragColor, texCoord*iResolution.xy); 16 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/drawable/ic_flash_off_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /sample/app/src/main/res/drawable/ic_flash_auto_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/negative.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform sampler2D iChannel0; 5 | varying vec2 texCoord; 6 | 7 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 8 | { 9 | vec4 mask = texture2D(iChannel0, fragCoord); 10 | vec4 color =vec4(1.0-mask.r, 1.0-mask.g, 1.0-mask.r,1.0); 11 | fragColor = color; 12 | } 13 | 14 | void main() { 15 | mainImage(gl_FragColor, texCoord); 16 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/drawable/ic_videocam_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/preview/CameraPreviewCallback.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.preview 2 | 3 | /** 4 | * Camera preview callback 5 | * 6 | * @author WngShhng (shouheng2015@gmail.com) 7 | * @version 2019/4/14 9:47 8 | */ 9 | interface CameraPreviewCallback { 10 | /** 11 | * The method will be called when the preview is available. 12 | * 13 | * @param cameraPreview the camera preview. 14 | */ 15 | fun onAvailable(cameraPreview: CameraPreview) 16 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/config/convert/ImageRawDataConverter.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.config.convert 2 | 3 | import android.media.Image 4 | 5 | /** 6 | * The image data convert. 7 | * 8 | * @author Jeff 9 | * @time 2020/10/12 23:46 10 | */ 11 | interface ImageRawDataConverter { 12 | /** 13 | * Convert from given format to NV21. 14 | * 15 | * @param image the image data 16 | * @return the image data in bytes 17 | */ 18 | fun convertToNV21(image: Image): ByteArray 19 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/gray.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform sampler2D iChannel0; 5 | varying vec2 texCoord; 6 | 7 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 8 | { 9 | vec4 mask = texture2D(iChannel0, fragCoord); 10 | float color = (mask.r + mask.g + mask.b) /3.0; 11 | vec4 tempColor =vec4(color, color, color,1.0); 12 | fragColor = tempColor; 13 | } 14 | 15 | void main() { 16 | mainImage(gl_FragColor, texCoord); 17 | } -------------------------------------------------------------------------------- /icamera/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/basic_deform.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform float iGlobalTime; 5 | uniform sampler2D iChannel0; 6 | varying vec2 texCoord; 7 | 8 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 9 | { 10 | float stongth = 0.3; 11 | vec2 uv = fragCoord.xy; 12 | float waveu = sin((uv.y + iGlobalTime) * 20.0) * 0.5 * 0.05 * stongth; 13 | fragColor = texture2D(iChannel0, uv + vec2(waveu, 0)); 14 | } 15 | 16 | void main() { 17 | mainImage(gl_FragColor, texCoord); 18 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/black_and_white.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform sampler2D iChannel0; 5 | varying vec2 texCoord; 6 | 7 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 8 | { 9 | vec4 mask = texture2D(iChannel0, fragCoord); 10 | float color = (mask.r + mask.g + mask.b) / 3.0; 11 | color = step(0.5, color); 12 | vec4 tempColor = vec4(color, color, color, 1.0); 13 | fragColor = tempColor; 14 | } 15 | 16 | void main() { 17 | mainImage(gl_FragColor, texCoord); 18 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/casting.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform sampler2D iChannel0; 5 | varying vec2 texCoord; 6 | 7 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 8 | { 9 | vec4 mask = texture2D(iChannel0, fragCoord); 10 | vec4 tempColor = vec4(mask.r*0.5/(mask.g + mask.b + 0.01), 11 | mask.g*0.5/(mask.r + mask.b + 0.01), 12 | mask.b*0.5/(mask.r + mask.g + 0.01), 13 | 1.0); 14 | fragColor = tempColor; 15 | } 16 | 17 | void main() { 18 | mainImage(gl_FragColor, texCoord); 19 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/enums/MediaType.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.enums 2 | 3 | import androidx.annotation.IntDef 4 | 5 | /** 6 | * Media type 7 | * 8 | * @author [WngShhng](mailto:shouheng2015@gmail.com) 9 | * @version 2019-12-28 16:29 10 | */ 11 | @IntDef(value = [MediaType.TYPE_PICTURE, MediaType.TYPE_VIDEO]) 12 | @kotlin.annotation.Retention(AnnotationRetention.SOURCE) 13 | annotation class MediaType { 14 | companion object { 15 | /** Picture */ 16 | const val TYPE_PICTURE = 0 17 | /** Video */ 18 | const val TYPE_VIDEO = 1 19 | } 20 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/edge_detection.fsh: -------------------------------------------------------------------------------- 1 | #extension GL_OES_standard_derivatives : enable 2 | precision mediump float; 3 | 4 | uniform vec3 iResolution; 5 | uniform sampler2D iChannel0; 6 | varying vec2 texCoord; 7 | 8 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 9 | { 10 | vec2 uv = fragCoord.xy; 11 | vec4 color = texture2D(iChannel0, fragCoord); 12 | float gray = length(color.rgb); 13 | fragColor = vec4(vec3(step(0.06, length(vec2(dFdx(gray), dFdy(gray))))), 1.0); 14 | } 15 | 16 | void main() { 17 | mainImage(gl_FragColor, texCoord); 18 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/enums/CameraFace.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.enums 2 | 3 | import androidx.annotation.IntDef 4 | 5 | /** 6 | * Camera face 7 | * 8 | * @author [WngShhng](mailto:shouheng2015@gmail.com) 9 | * @version 2019-12-28 16:38 10 | */ 11 | @IntDef(value = [CameraFace.FACE_REAR, CameraFace.FACE_FRONT]) 12 | @kotlin.annotation.Retention(AnnotationRetention.SOURCE) 13 | annotation class CameraFace { 14 | companion object { 15 | /** Rear camera */ 16 | const val FACE_REAR = 0x0000 17 | /** Front camera */ 18 | const val FACE_FRONT = 0x0001 19 | } 20 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/enums/DeviceDefaultOrientation.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.enums 2 | 3 | import androidx.annotation.IntDef 4 | 5 | /** 6 | * @author [WngShhng](mailto:shouheng2015@gmail.com) 7 | * @version 2020-08-27 10:07 8 | */ 9 | @IntDef(DeviceDefaultOrientation.ORIENTATION_PORTRAIT, 10 | DeviceDefaultOrientation.ORIENTATION_LANDSCAPE) 11 | @kotlin.annotation.Retention(AnnotationRetention.SOURCE) 12 | annotation class DeviceDefaultOrientation { 13 | companion object { 14 | const val ORIENTATION_PORTRAIT = 0x01 15 | const val ORIENTATION_LANDSCAPE = 0x02 16 | } 17 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/nostalgia.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform sampler2D iChannel0; 5 | varying vec2 texCoord; 6 | 7 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 8 | { 9 | vec4 mask = texture2D(iChannel0, fragCoord); 10 | vec4 tempColor = vec4(0.393 * mask.r + 0.769 * mask.g + 0.189 * mask.b, 11 | 0.349 * mask.r + 0.686 * mask.g + 0.168 * mask.b, 12 | 0.272 * mask.r + 0.534 * mask.g + 0.131 * mask.b, 1.0); 13 | fragColor = tempColor; 14 | } 15 | 16 | void main() { 17 | mainImage(gl_FragColor, texCoord); 18 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/enums/CameraType.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.enums 2 | 3 | import androidx.annotation.IntDef 4 | 5 | /** 6 | * Camera1 or camera2 7 | * 8 | * @author [WngShhng](mailto:shouheng2015@gmail.com) 9 | * @version 2019-12-28 16:39 10 | */ 11 | @IntDef(value = [CameraType.TYPE_CAMERA1, CameraType.TYPE_CAMERA2]) 12 | @kotlin.annotation.Retention(AnnotationRetention.SOURCE) 13 | annotation class CameraType { 14 | companion object { 15 | /** Camera1 */ 16 | const val TYPE_CAMERA1 = 0x0100 17 | /** Camera2 */ 18 | const val TYPE_CAMERA2 = 0x0200 19 | } 20 | } -------------------------------------------------------------------------------- /sample/.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/mirror.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform sampler2D iChannel0; 5 | varying vec2 texCoord; 6 | 7 | 8 | 9 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 10 | { 11 | vec2 flipCoord = vec2(1.0-fragCoord.x, fragCoord.y); 12 | if(flipCoord.x >= 0.5){ 13 | fragColor = texture2D(iChannel0, vec2( flipCoord.x - 0.5, flipCoord.y )); 14 | } else { 15 | fragColor = texture2D(iChannel0, vec2( 0.5 - flipCoord.x,flipCoord.y )); 16 | } 17 | } 18 | 19 | void main() { 20 | mainImage(gl_FragColor, texCoord); 21 | } 22 | -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/enums/FlashMode.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.enums 2 | 3 | import androidx.annotation.IntDef 4 | 5 | /** 6 | * Flash mode 7 | * 8 | * @author WngShhng (shouheng2015@gmail.com) 9 | * @version 2019/4/14 21:57 10 | */ 11 | @IntDef(FlashMode.FLASH_ON, FlashMode.FLASH_OFF, FlashMode.FLASH_AUTO) 12 | @kotlin.annotation.Retention(AnnotationRetention.SOURCE) 13 | annotation class FlashMode { 14 | companion object { 15 | /** Flash on */ 16 | const val FLASH_ON = 0 17 | /** Flash off */ 18 | const val FLASH_OFF = 1 19 | /** Auto */ 20 | const val FLASH_AUTO = 2 21 | } 22 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/blue_orange.fsh: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | 3 | uniform vec3 iResolution; 4 | uniform float iGlobalTime; 5 | uniform sampler2D iChannel0; 6 | varying vec2 texCoord; 7 | 8 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 9 | { 10 | vec2 uv = fragCoord.xy; 11 | 12 | vec3 tex = texture2D( iChannel0, uv ).rgb; 13 | float shade = dot(tex, vec3(0.333333)); 14 | 15 | vec3 col = mix(vec3(0.1, 0.36, 0.8) * (1.0-2.0*abs(shade-0.5)), vec3(1.06, 0.8, 0.55), 1.0-shade); 16 | 17 | fragColor = vec4(col,1.0); 18 | } 19 | 20 | void main() { 21 | mainImage(gl_FragColor, texCoord); 22 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/cartoon.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform sampler2D iChannel0; 5 | varying vec2 texCoord; 6 | 7 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 8 | { 9 | vec4 color = texture2D(iChannel0, fragCoord); 10 | float newR = abs(color.r + color.g * 2.0 - color.b) * color.r; 11 | float newG = abs(color.r + color.b * 2.0 - color.g) * color.r; 12 | float newB = abs(color.r + color.b * 2.0 - color.g) * color.g; 13 | vec4 newColor = vec4(newR, newG, newB, 1.0); 14 | fragColor = newColor; 15 | } 16 | 17 | void main() { 18 | mainImage(gl_FragColor, texCoord); 19 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/util/XUtils.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.util 2 | 3 | import android.content.Context 4 | 5 | /** 6 | * Utils class for current library. 7 | * 8 | * @author WngShhng (shouheng2015@gmail.com) 9 | * @version 2019/4/14 9:34 10 | */ 11 | object XUtils { 12 | 13 | fun dp2Px(context: Context, dpValues: Float): Int { 14 | val scale = context.resources.displayMetrics.density 15 | return (dpValues * scale + 0.5f).toInt() 16 | } 17 | 18 | fun sp2Px(context: Context, spValues: Float): Int { 19 | val fontScale = context.resources.displayMetrics.scaledDensity 20 | return (spValues * fontScale + 0.5f).toInt() 21 | } 22 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/drawable/ic_photo_camera_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/refraction.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform float iGlobalTime; 5 | uniform sampler2D iChannel0; 6 | uniform sampler2D iChannel1; 7 | varying vec2 texCoord; 8 | 9 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 10 | { 11 | vec2 uv = fragCoord.xy; 12 | 13 | vec4 bump = texture2D(iChannel1, uv + iGlobalTime * 0.05); 14 | 15 | vec2 vScale = vec2 (0.01, 0.01); 16 | vec2 newUV = uv + bump.xy * vScale.xy; 17 | 18 | vec4 col = texture2D(iChannel0, newUV); 19 | 20 | fragColor = vec4(col.xyz, 1.0); 21 | } 22 | 23 | void main() { 24 | mainImage(gl_FragColor, texCoord); 25 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/enums/PreviewViewType.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.enums 2 | 3 | import androidx.annotation.IntDef 4 | 5 | /** 6 | * Camera preview view type. 7 | * 8 | * @author [WngShhng](mailto:shouheng2015@gmail.com) 9 | * @version 2019-12-28 11:26 10 | */ 11 | @IntDef(value = [PreviewViewType.SURFACE_VIEW, PreviewViewType.TEXTURE_VIEW]) 12 | @kotlin.annotation.Retention(AnnotationRetention.SOURCE) 13 | annotation class PreviewViewType { 14 | companion object { 15 | /** [android.view.SurfaceView] will be used */ 16 | const val SURFACE_VIEW = 0 17 | 18 | /** [android.view.TextureView] will be used */ 19 | const val TEXTURE_VIEW = 1 20 | } 21 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/triple.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform sampler2D iChannel0; 5 | varying vec2 texCoord; 6 | 7 | uniform float u_time; 8 | 9 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 10 | { 11 | if (fragCoord.y <= 0.333){ 12 | fragColor = texture2D(iChannel0, vec2(fragCoord.x,fragCoord.y + 0.333)); 13 | }else if(fragCoord.y > 0.333 && fragCoord.y<= 0.666){ 14 | fragColor = texture2D(iChannel0, fragCoord); 15 | }else{ 16 | fragColor = texture2D(iChannel0, vec2(fragCoord.x,fragCoord.y - 0.333)); 17 | } 18 | } 19 | 20 | void main() { 21 | mainImage(gl_FragColor, texCoord); 22 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/config/creator/impl/SurfaceViewOnlyCreator.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.config.creator.impl 2 | 3 | import android.content.Context 4 | import android.view.ViewGroup 5 | import me.shouheng.icamera.config.creator.CameraPreviewCreator 6 | import me.shouheng.icamera.preview.CameraPreview 7 | import me.shouheng.icamera.preview.impl.SurfacePreview 8 | 9 | /** 10 | * @author [WngShhng](mailto:shouheng2015@gmail.com) 11 | * @version 2020-08-31 10:49 12 | */ 13 | class SurfaceViewOnlyCreator : CameraPreviewCreator { 14 | override fun create( 15 | context: Context, 16 | parent: ViewGroup 17 | ): CameraPreview { 18 | return SurfacePreview(context, parent) 19 | } 20 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/config/creator/impl/TextureViewOnlyCreator.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.config.creator.impl 2 | 3 | import android.content.Context 4 | import android.view.ViewGroup 5 | import me.shouheng.icamera.config.creator.CameraPreviewCreator 6 | import me.shouheng.icamera.preview.CameraPreview 7 | import me.shouheng.icamera.preview.impl.TexturePreview 8 | 9 | /** 10 | * @author [WngShhng](mailto:shouheng2015@gmail.com) 11 | * @version 2020-08-31 10:49 12 | */ 13 | class TextureViewOnlyCreator : CameraPreviewCreator { 14 | override fun create( 15 | context: Context, 16 | parent: ViewGroup 17 | ): CameraPreview { 18 | return TexturePreview(context, parent) 19 | } 20 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/water_reflection.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform sampler2D iChannel0; 5 | varying vec2 texCoord; 6 | 7 | float waterLevel = 0.5; 8 | float waveAmplitude = 0.01; 9 | 10 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 11 | { 12 | if(fragCoord.y >= waterLevel){ 13 | fragColor = texture2D(iChannel0, fragCoord); 14 | }else{ 15 | fragColor = texture2D(iChannel0,vec2(fragCoord.x + fract(sin(dot(fragCoord.xy ,vec2(12.9898,78.233))) * 43758.5453) * waveAmplitude, 16 | 2.0 * waterLevel - fragCoord.y)); 17 | } 18 | } 19 | 20 | void main() { 21 | mainImage(gl_FragColor, texCoord); 22 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/config/creator/CameraManagerCreator.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.config.creator 2 | 3 | import android.content.Context 4 | import me.shouheng.icamera.manager.CameraManager 5 | import me.shouheng.icamera.preview.CameraPreview 6 | 7 | /** 8 | * Creator for [CameraManager]. 9 | * 10 | * @author WngShhng (shouheng2015@gmail.com) 11 | * @version 2019/4/13 22:55 12 | */ 13 | interface CameraManagerCreator { 14 | /** 15 | * Method used to create [CameraManager]. 16 | * 17 | * @param context the context 18 | * @param cameraPreview the [CameraPreview] 19 | * @return CameraManager object. 20 | */ 21 | fun create(context: Context, cameraPreview: CameraPreview): CameraManager 22 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/drawable/ic_circle_white.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/config/creator/CameraPreviewCreator.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.config.creator 2 | 3 | import android.content.Context 4 | import android.view.ViewGroup 5 | import me.shouheng.icamera.preview.CameraPreview 6 | 7 | /** 8 | * The creator for [CameraPreview]. 9 | * 10 | * @author WngShhng (shouheng2015@gmail.com) 11 | * @version 2019/4/13 22:56 12 | */ 13 | interface CameraPreviewCreator { 14 | /** 15 | * Method used to create [CameraPreview]. 16 | * 17 | * @param context the context to create the preview view. 18 | * @param parent the parent view of the preview. 19 | * @return CameraPreview object. 20 | */ 21 | fun create(context: Context, parent: ViewGroup): CameraPreview 22 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/config/creator/impl/Camera1OnlyCreator.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.config.creator.impl 2 | 3 | import android.content.Context 4 | import me.shouheng.icamera.config.creator.CameraManagerCreator 5 | import me.shouheng.icamera.manager.CameraManager 6 | import me.shouheng.icamera.manager.impl.Camera1Manager 7 | import me.shouheng.icamera.preview.CameraPreview 8 | 9 | /** 10 | * @author [WngShhng](mailto:shouheng2015@gmail.com) 11 | * @version 2020-08-31 10:47 12 | */ 13 | class Camera1OnlyCreator : CameraManagerCreator { 14 | override fun create( 15 | context: Context, 16 | cameraPreview: CameraPreview 17 | ): CameraManager { 18 | return Camera1Manager(cameraPreview) 19 | } 20 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/drawable/ic_party_mode_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/triangles_mosaic.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform sampler2D iChannel0; 5 | varying vec2 texCoord; 6 | 7 | vec2 tile_num = vec2(40.0,20.0); 8 | 9 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 10 | { 11 | vec2 uv = fragCoord.xy; 12 | vec2 uv2 = floor(uv*tile_num)/tile_num; 13 | uv -= uv2; 14 | uv *= tile_num; 15 | fragColor = texture2D( iChannel0, uv2 + vec2(step(1.0-uv.y,uv.x)/(2.0*tile_num.x), 16 | //0, 17 | step(uv.x,uv.y)/(2.0*tile_num.y) 18 | //0 19 | ) ); 20 | } 21 | 22 | void main() { 23 | mainImage(gl_FragColor, texCoord); 24 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/config/convert/ImageRawDataConverterImpl.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.config.convert 2 | 3 | import android.graphics.ImageFormat 4 | import android.media.Image 5 | import android.os.Build 6 | import androidx.annotation.RequiresApi 7 | import me.shouheng.icamera.util.ImageHelper.convertYUV_420_888toNV21 8 | 9 | /** 10 | * The default image raw data converter implementation. 11 | * 12 | * @author Jeff 13 | * @time 2020/10/12 23:49 14 | */ 15 | class ImageRawDataConverterImpl : ImageRawDataConverter { 16 | @RequiresApi(api = Build.VERSION_CODES.KITKAT) 17 | override fun convertToNV21(image: Image): ByteArray { 18 | return if (image.format == ImageFormat.YUV_420_888) { 19 | convertYUV_420_888toNV21(image) 20 | } else ByteArray(0) 21 | } 22 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/mapping.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform float iGlobalTime; 5 | uniform sampler2D iChannel0; 6 | uniform sampler2D iChannel1; 7 | varying vec2 texCoord; 8 | 9 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 10 | { 11 | 12 | vec2 pos = fragCoord.xy; 13 | vec2 uv2 = vec2( fragCoord.xy / iResolution.xy ); 14 | vec4 sound = texture2D( iChannel0, uv2 ); 15 | pos.x = pos.x + 150.0 * sound.r; 16 | pos.y = pos.y + 150.0 * sound.b; 17 | vec2 uv = pos / iResolution.xy; 18 | 19 | vec4 col = texture2D( iChannel1, uv ); 20 | 21 | col.a += 1.0 - sin( col.x - col.y + iGlobalTime * 0.1 ); 22 | 23 | fragColor = col * sound.r; 24 | } 25 | 26 | void main() { 27 | mainImage(gl_FragColor, texCoord * iResolution.xy); 28 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/enums/CameraSizeFor.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.enums 2 | 3 | import androidx.annotation.IntDef 4 | 5 | /** 6 | * Camera size for preview, picture, video, etc. 7 | * 8 | * @author [WngShhng](mailto:shouheng2015@gmail.com) 9 | * @version 2019-12-28 16:38 10 | */ 11 | @IntDef(value = [ 12 | CameraSizeFor.SIZE_FOR_PREVIEW, 13 | CameraSizeFor.SIZE_FOR_PICTURE, 14 | CameraSizeFor.SIZE_FOR_VIDEO]) 15 | @kotlin.annotation.Retention(AnnotationRetention.SOURCE) 16 | annotation class CameraSizeFor { 17 | companion object { 18 | /** Camera size for preview */ 19 | const val SIZE_FOR_PREVIEW = 0x0010 20 | 21 | /** Camera size for picture */ 22 | const val SIZE_FOR_PICTURE = 0x0020 23 | 24 | /** Camera size for video */ 25 | const val SIZE_FOR_VIDEO = 0x0040 26 | } 27 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/config/creator/impl/Camera2OnlyCreator.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.config.creator.impl 2 | 3 | import android.content.Context 4 | import android.os.Build 5 | import androidx.annotation.RequiresApi 6 | import me.shouheng.icamera.config.creator.CameraManagerCreator 7 | import me.shouheng.icamera.manager.CameraManager 8 | import me.shouheng.icamera.manager.impl.Camera2Manager 9 | import me.shouheng.icamera.preview.CameraPreview 10 | 11 | /** 12 | * @author [WngShhng](mailto:shouheng2015@gmail.com) 13 | * @version 2020-08-31 10:48 14 | */ 15 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 16 | class Camera2OnlyCreator : CameraManagerCreator { 17 | override fun create( 18 | context: Context, 19 | cameraPreview: CameraPreview 20 | ): CameraManager { 21 | return Camera2Manager(cameraPreview) 22 | } 23 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/relief.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform sampler2D iChannel0; 5 | varying vec2 texCoord; 6 | 7 | const highp vec3 transMatrix = vec3(0.2125, 0.7154, 0.0721); 8 | const vec4 bgColor = vec4(0.5, 0.5, 0.5, 1.0); 9 | 10 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 11 | { 12 | vec2 currentUV = fragCoord; 13 | vec2 preUV = vec2(currentUV.x-5.0/iResolution.x, currentUV.y-5.0/iResolution.y); 14 | vec4 currentMask = texture2D(iChannel0, currentUV); 15 | vec4 preMask = texture2D(iChannel0, preUV); 16 | vec4 delColor = currentMask - preMask; 17 | float luminance = dot(delColor.rgb, transMatrix); 18 | fragColor = vec4(vec3(luminance), 0.0) + bgColor; 19 | } 20 | 21 | void main() { 22 | mainImage(gl_FragColor, texCoord); 23 | } 24 | -------------------------------------------------------------------------------- /icamera/src/main/res/layout/layout_focus_marker.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | 11 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/enums/SensorPosition.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.enums 2 | 3 | import androidx.annotation.IntDef 4 | 5 | /** 6 | * @author [WngShhng](mailto:shouheng2015@gmail.com) 7 | * @version 2020-08-27 10:13 8 | */ 9 | @IntDef( 10 | SensorPosition.SENSOR_POSITION_UP, 11 | SensorPosition.SENSOR_POSITION_UP_SIDE_DOWN, 12 | SensorPosition.SENSOR_POSITION_LEFT, 13 | SensorPosition.SENSOR_POSITION_RIGHT, 14 | SensorPosition.SENSOR_POSITION_UNSPECIFIED 15 | ) 16 | @kotlin.annotation.Retention(AnnotationRetention.SOURCE) 17 | annotation class SensorPosition { 18 | companion object { 19 | const val SENSOR_POSITION_UP = 90 20 | const val SENSOR_POSITION_UP_SIDE_DOWN = 270 21 | const val SENSOR_POSITION_LEFT = 0 22 | const val SENSOR_POSITION_RIGHT = 180 23 | const val SENSOR_POSITION_UNSPECIFIED = -1 24 | } 25 | } -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/GrayFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class GrayFilter extends CameraFilter { 10 | private int program; 11 | 12 | public GrayFilter(Context context) { 13 | super(context); 14 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.gray); 15 | } 16 | 17 | @Override 18 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 19 | setupShaderInputs(program, 20 | new int[]{canvasWidth, canvasHeight}, 21 | new int[]{cameraTexId}, 22 | new int[][]{}); 23 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/SwirlFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class SwirlFilter extends CameraFilter { 10 | private int program; 11 | 12 | public SwirlFilter(Context context) { 13 | super(context); 14 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.swirl); 15 | } 16 | 17 | @Override 18 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 19 | setupShaderInputs(program, 20 | new int[]{canvasWidth, canvasHeight}, 21 | new int[]{cameraTexId}, 22 | new int[][]{}); 23 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/MirrorFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class MirrorFilter extends CameraFilter { 10 | private int program; 11 | 12 | public MirrorFilter(Context context) { 13 | super(context); 14 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.mirror); 15 | } 16 | 17 | @Override 18 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 19 | setupShaderInputs(program, 20 | new int[]{canvasWidth, canvasHeight}, 21 | new int[]{cameraTexId}, 22 | new int[][]{}); 23 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/ReliefFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class ReliefFilter extends CameraFilter { 10 | private int program; 11 | 12 | public ReliefFilter(Context context) { 13 | super(context); 14 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.relief); 15 | } 16 | 17 | @Override 18 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 19 | setupShaderInputs(program, 20 | new int[]{canvasWidth, canvasHeight}, 21 | new int[]{cameraTexId}, 22 | new int[][]{}); 23 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/CartoonFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class CartoonFilter extends CameraFilter { 10 | private int program; 11 | 12 | public CartoonFilter(Context context) { 13 | super(context); 14 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.cartoon); 15 | } 16 | 17 | @Override 18 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 19 | setupShaderInputs(program, 20 | new int[]{canvasWidth, canvasHeight}, 21 | new int[]{cameraTexId}, 22 | new int[][]{}); 23 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/CastingFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class CastingFilter extends CameraFilter { 10 | private int program; 11 | 12 | public CastingFilter(Context context) { 13 | super(context); 14 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.casting); 15 | } 16 | 17 | @Override 18 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 19 | setupShaderInputs(program, 20 | new int[]{canvasWidth, canvasHeight}, 21 | new int[]{cameraTexId}, 22 | new int[][]{}); 23 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/NegativeFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class NegativeFilter extends CameraFilter { 10 | private int program; 11 | 12 | public NegativeFilter(Context context) { 13 | super(context); 14 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.negative); 15 | } 16 | 17 | @Override 18 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 19 | setupShaderInputs(program, 20 | new int[]{canvasWidth, canvasHeight}, 21 | new int[]{cameraTexId}, 22 | new int[][]{}); 23 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/TripleFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | 10 | public class TripleFilter extends CameraFilter { 11 | private int program; 12 | 13 | public TripleFilter(Context context) { 14 | super(context); 15 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.triple); 16 | } 17 | 18 | @Override 19 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 20 | setupShaderInputs(program, 21 | new int[]{canvasWidth, canvasHeight}, 22 | new int[]{cameraTexId}, 23 | new int[][]{}); 24 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/NostalgiaFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class NostalgiaFilter extends CameraFilter { 10 | private int program; 11 | 12 | public NostalgiaFilter(Context context) { 13 | super(context); 14 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.nostalgia); 15 | } 16 | 17 | @Override 18 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 19 | setupShaderInputs(program, 20 | new int[]{canvasWidth, canvasHeight}, 21 | new int[]{cameraTexId}, 22 | new int[][]{}); 23 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/contrast.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform float iGlobalTime; 5 | uniform sampler2D iChannel0; 6 | varying vec2 texCoord; 7 | 8 | float remap(float value, float inputMin, float inputMax, float outputMin, float outputMax) 9 | { 10 | return (value - inputMin) * ((outputMax - outputMin) / (inputMax - inputMin)) + outputMin; 11 | } 12 | 13 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 14 | { 15 | vec2 uv = fragCoord.xy; 16 | float normalizedContrast = 1.0; 17 | float contrast = remap(normalizedContrast, 0.0, 1.0, 0.2 /*min*/, 4.0 /*max*/); 18 | 19 | vec4 srcColor = texture2D(iChannel0, uv); 20 | vec4 dstColor = vec4((srcColor.rgb - vec3(0.5)) * contrast + vec3(0.5), 1.0); 21 | fragColor = clamp(dstColor, 0.0, 1.0); 22 | } 23 | 24 | void main() { 25 | mainImage(gl_FragColor, texCoord); 26 | } -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/BlackAndWhiteFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class BlackAndWhiteFilter extends CameraFilter { 10 | private int program; 11 | 12 | public BlackAndWhiteFilter(Context context) { 13 | super(context); 14 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.black_and_white); 15 | } 16 | 17 | @Override 18 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 19 | setupShaderInputs(program, 20 | new int[]{canvasWidth, canvasHeight}, 21 | new int[]{cameraTexId}, 22 | new int[][]{}); 23 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/HexagonMosaicFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class HexagonMosaicFilter extends CameraFilter { 10 | private int program; 11 | 12 | public HexagonMosaicFilter(Context context) { 13 | super(context); 14 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.hexagon_mosaic); 15 | } 16 | 17 | @Override 18 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 19 | setupShaderInputs(program, 20 | new int[]{canvasWidth, canvasHeight}, 21 | new int[]{cameraTexId}, 22 | new int[][]{}); 23 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/WaterReflectionFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class WaterReflectionFilter extends CameraFilter { 10 | private int program; 11 | 12 | public WaterReflectionFilter(Context context) { 13 | super(context); 14 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.water_reflection); 15 | } 16 | 17 | @Override 18 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 19 | setupShaderInputs(program, 20 | new int[]{canvasWidth, canvasHeight}, 21 | new int[]{cameraTexId}, 22 | new int[][]{}); 23 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/CrackedFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class CrackedFilter extends CameraFilter { 10 | private int program; 11 | 12 | public CrackedFilter(Context context) { 13 | super(context); 14 | 15 | // Build shaders 16 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.cracked); 17 | } 18 | 19 | @Override 20 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 21 | setupShaderInputs(program, 22 | new int[]{canvasWidth, canvasHeight}, 23 | new int[]{cameraTexId}, 24 | new int[][]{}); 25 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/MoneyFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class MoneyFilter extends CameraFilter { 10 | private int program; 11 | 12 | public MoneyFilter(Context context) { 13 | super(context); 14 | 15 | // Build shaders 16 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.money_filter); 17 | } 18 | 19 | @Override 20 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 21 | setupShaderInputs(program, 22 | new int[]{canvasWidth, canvasHeight}, 23 | new int[]{cameraTexId}, 24 | new int[][]{}); 25 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/AsciiArtFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class AsciiArtFilter extends CameraFilter { 10 | private int program; 11 | 12 | public AsciiArtFilter(Context context) { 13 | super(context); 14 | 15 | // Build shaders 16 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.ascii_art); 17 | } 18 | 19 | @Override 20 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 21 | setupShaderInputs(program, 22 | new int[]{canvasWidth, canvasHeight}, 23 | new int[]{cameraTexId}, 24 | new int[][]{}); 25 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/ContrastFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class ContrastFilter extends CameraFilter { 10 | private int program; 11 | 12 | public ContrastFilter(Context context) { 13 | super(context); 14 | 15 | // Build shaders 16 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.contrast); 17 | } 18 | 19 | @Override 20 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 21 | setupShaderInputs(program, 22 | new int[]{canvasWidth, canvasHeight}, 23 | new int[]{cameraTexId}, 24 | new int[][]{}); 25 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/PixelizeFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class PixelizeFilter extends CameraFilter { 10 | private int program; 11 | 12 | public PixelizeFilter(Context context) { 13 | super(context); 14 | 15 | // Build shaders 16 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.pixelize); 17 | } 18 | 19 | @Override 20 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 21 | setupShaderInputs(program, 22 | new int[]{canvasWidth, canvasHeight}, 23 | new int[]{cameraTexId}, 24 | new int[][]{}); 25 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/BlueorangeFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class BlueorangeFilter extends CameraFilter { 10 | private int program; 11 | 12 | public BlueorangeFilter(Context context) { 13 | super(context); 14 | 15 | // Build shaders 16 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.blue_orange); 17 | } 18 | 19 | @Override 20 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 21 | setupShaderInputs(program, 22 | new int[]{canvasWidth, canvasHeight}, 23 | new int[]{cameraTexId}, 24 | new int[][]{}); 25 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/CrosshatchFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class CrosshatchFilter extends CameraFilter { 10 | private int program; 11 | 12 | public CrosshatchFilter(Context context) { 13 | super(context); 14 | 15 | // Build shaders 16 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.crosshatch); 17 | } 18 | 19 | @Override 20 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 21 | setupShaderInputs(program, 22 | new int[]{canvasWidth, canvasHeight}, 23 | new int[]{cameraTexId}, 24 | new int[][]{}); 25 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/NoiseWarpFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class NoiseWarpFilter extends CameraFilter { 10 | private int program; 11 | 12 | public NoiseWarpFilter(Context context) { 13 | super(context); 14 | 15 | // Build shaders 16 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.noise_warp); 17 | } 18 | 19 | @Override 20 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 21 | setupShaderInputs(program, 22 | new int[]{canvasWidth, canvasHeight}, 23 | new int[]{cameraTexId}, 24 | new int[][]{}); 25 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/OriginalFilter.java: -------------------------------------------------------------------------------- 1 | 2 | package me.shouheng.icamerasample.filter; 3 | 4 | import android.content.Context; 5 | import android.opengl.GLES20; 6 | 7 | import me.shouheng.icamerasample.R; 8 | import me.shouheng.icamerasample.render.MyGLUtils; 9 | 10 | public class OriginalFilter extends CameraFilter { 11 | private int program; 12 | 13 | public OriginalFilter(Context context) { 14 | super(context); 15 | 16 | // Build shaders 17 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.original); 18 | } 19 | 20 | @Override 21 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 22 | setupShaderInputs(program, 23 | new int[]{canvasWidth, canvasHeight}, 24 | new int[]{cameraTexId}, 25 | new int[][]{}); 26 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/TileMosaicFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class TileMosaicFilter extends CameraFilter { 10 | private int program; 11 | 12 | public TileMosaicFilter(Context context) { 13 | super(context); 14 | 15 | // Build shaders 16 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.tile_mosaic); 17 | } 18 | 19 | @Override 20 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 21 | setupShaderInputs(program, 22 | new int[]{canvasWidth, canvasHeight}, 23 | new int[]{cameraTexId}, 24 | new int[][]{}); 25 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/BasicDeformFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class BasicDeformFilter extends CameraFilter { 10 | private int program; 11 | 12 | public BasicDeformFilter(Context context) { 13 | super(context); 14 | 15 | // Build shaders 16 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.basic_deform); 17 | } 18 | 19 | @Override 20 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 21 | setupShaderInputs(program, 22 | new int[]{canvasWidth, canvasHeight}, 23 | new int[]{cameraTexId}, 24 | new int[][]{}); 25 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/LegofiedFilter.java: -------------------------------------------------------------------------------- 1 | 2 | package me.shouheng.icamerasample.filter; 3 | 4 | import android.content.Context; 5 | import android.opengl.GLES20; 6 | 7 | import me.shouheng.icamerasample.R; 8 | import me.shouheng.icamerasample.render.MyGLUtils; 9 | 10 | 11 | public class LegofiedFilter extends CameraFilter { 12 | private int program; 13 | 14 | public LegofiedFilter(Context context) { 15 | super(context); 16 | 17 | // Build shaders 18 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.legofied); 19 | } 20 | 21 | @Override 22 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 23 | setupShaderInputs(program, 24 | new int[]{canvasWidth, canvasHeight}, 25 | new int[]{cameraTexId}, 26 | new int[][]{}); 27 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/EdgeDetectionFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class EdgeDetectionFilter extends CameraFilter { 10 | private int program; 11 | 12 | public EdgeDetectionFilter(Context context) { 13 | super(context); 14 | 15 | // Build shaders 16 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.edge_detection); 17 | } 18 | 19 | @Override 20 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 21 | setupShaderInputs(program, 22 | new int[]{canvasWidth, canvasHeight}, 23 | new int[]{cameraTexId}, 24 | new int[][]{}); 25 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/PolygonizationFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class PolygonizationFilter extends CameraFilter { 10 | private int program; 11 | 12 | public PolygonizationFilter(Context context) { 13 | super(context); 14 | 15 | // Build shaders 16 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.polygonization); 17 | } 18 | 19 | @Override 20 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 21 | setupShaderInputs(program, 22 | new int[]{canvasWidth, canvasHeight}, 23 | new int[]{cameraTexId}, 24 | new int[][]{}); 25 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/EMInterferenceFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class EMInterferenceFilter extends CameraFilter { 10 | private int program; 11 | 12 | public EMInterferenceFilter(Context context) { 13 | super(context); 14 | 15 | // Build shaders 16 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.em_interference); 17 | } 18 | 19 | @Override 20 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 21 | setupShaderInputs(program, 22 | new int[]{canvasWidth, canvasHeight}, 23 | new int[]{cameraTexId}, 24 | new int[][]{}); 25 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/voronoi_buf_c.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform int iFrame; 4 | uniform vec3 iResolution; 5 | uniform vec3 iChannelResolution[2]; 6 | uniform float iGlobalTime; 7 | uniform sampler2D iChannel0; 8 | uniform sampler2D iChannel1; 9 | varying vec2 texCoord; 10 | 11 | // A secondary buffer to get clean Voronoi every N-th frame 12 | 13 | // this must be in sync with JFA algorithm constant 14 | const float c_maxSteps = 10.0; 15 | 16 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 17 | { 18 | vec2 uv = fragCoord.xy / iResolution.xy; 19 | if (mod(float(iFrame+1),c_maxSteps) < .5) { 20 | fragColor = texture2D(iChannel1, uv); // update to new voronoi cell 21 | } else { 22 | fragColor = texture2D(iChannel0, uv); // no change 23 | } 24 | } 25 | 26 | 27 | void main() { 28 | mainImage(gl_FragColor, texCoord*iResolution.xy); 29 | } -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/LichtensteinEsqueFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class LichtensteinEsqueFilter extends CameraFilter { 10 | private int program; 11 | 12 | public LichtensteinEsqueFilter(Context context) { 13 | super(context); 14 | 15 | // Build shaders 16 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.lichtenstein_esque); 17 | } 18 | 19 | @Override 20 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 21 | setupShaderInputs(program, 22 | new int[]{canvasWidth, canvasHeight}, 23 | new int[]{cameraTexId}, 24 | new int[][]{}); 25 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/TrianglesMosaicFilter.java: -------------------------------------------------------------------------------- 1 | 2 | package me.shouheng.icamerasample.filter; 3 | 4 | import android.content.Context; 5 | import android.opengl.GLES20; 6 | 7 | import me.shouheng.icamerasample.R; 8 | import me.shouheng.icamerasample.render.MyGLUtils; 9 | 10 | 11 | public class TrianglesMosaicFilter extends CameraFilter { 12 | private int program; 13 | 14 | public TrianglesMosaicFilter(Context context) { 15 | super(context); 16 | 17 | // Build shaders 18 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.triangles_mosaic); 19 | } 20 | 21 | @Override 22 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 23 | setupShaderInputs(program, 24 | new int[]{canvasWidth, canvasHeight}, 25 | new int[]{cameraTexId}, 26 | new int[][]{}); 27 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/ChromaticAberrationFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | public class ChromaticAberrationFilter extends CameraFilter { 10 | private int program; 11 | 12 | public ChromaticAberrationFilter(Context context) { 13 | super(context); 14 | 15 | // Build shaders 16 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.chromatic_aberration); 17 | } 18 | 19 | @Override 20 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 21 | setupShaderInputs(program, 22 | new int[]{canvasWidth, canvasHeight}, 23 | new int[]{cameraTexId}, 24 | new int[][]{}); 25 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sample/app/src/main/res/drawable/ic_settings_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /sample/.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 22 | 23 | -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/chromatic_aberration.fsh: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | 3 | uniform vec3 iResolution; 4 | uniform float iGlobalTime; 5 | uniform sampler2D iChannel0; 6 | varying vec2 texCoord; 7 | 8 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 9 | { 10 | vec2 uv = fragCoord.xy; 11 | 12 | float amount = 0.0; 13 | 14 | amount = (1.0 + sin(iGlobalTime*6.0)) * 0.5; 15 | amount *= 1.0 + sin(iGlobalTime*16.0) * 0.5; 16 | amount *= 1.0 + sin(iGlobalTime*19.0) * 0.5; 17 | amount *= 1.0 + sin(iGlobalTime*27.0) * 0.5; 18 | amount = pow(amount, 3.0); 19 | 20 | amount *= 0.05; 21 | 22 | vec3 col; 23 | col.r = texture2D( iChannel0, vec2(uv.x+amount,uv.y) ).r; 24 | col.g = texture2D( iChannel0, uv ).g; 25 | col.b = texture2D( iChannel0, vec2(uv.x-amount,uv.y) ).b; 26 | 27 | col *= (1.0 - amount * 0.5); 28 | 29 | fragColor = vec4(col,1.0); 30 | } 31 | 32 | 33 | void main() { 34 | mainImage(gl_FragColor, texCoord); 35 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/listener/CameraPreviewListener.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.listener 2 | 3 | import me.shouheng.icamera.config.size.Size 4 | 5 | /** 6 | * The camera preview callback 7 | * 8 | * @author WngShhng (shouheng2015@gmail.com) 9 | * @version 2020/9/1 21:36 10 | */ 11 | interface CameraPreviewListener { 12 | /** 13 | * On get the preview frame data. For camera2, the image format will always be 14 | * [android.graphics.ImageFormat.NV21]. For camera1 the image format will be 15 | * NV21 if you didn't set preview image format by calling 16 | * [Camera.Parameters.setPreviewFormat], else the returned byte array and 17 | * image format will be the format you set. 18 | * 19 | * @param data the image data byte array 20 | * @param size the preview image size 21 | * @param format the format of [android.graphics.ImageFormat] 22 | * 23 | * @see android.graphics.ImageFormat 24 | */ 25 | fun onPreviewFrame(data: ByteArray, size: Size, format: Int) 26 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/legofied.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform sampler2D iChannel0; 5 | varying vec2 texCoord; 6 | 7 | float c = 0.02; //amout of blocks = c*iResolution.x 8 | 9 | void mainImage( out vec4 fragColor, in vec2 fragCoord ){ 10 | //blocked pixel coordinate 11 | vec2 middle = floor(fragCoord*c+.5)/c; 12 | 13 | vec3 color = texture2D(iChannel0, middle/iResolution.xy).rgb; 14 | 15 | //lego block effects 16 | //stud 17 | float dis = distance(fragCoord,middle)*c*2.; 18 | if(dis<.65&&dis>.55){ 19 | color *= dot(vec2(0.707),normalize(fragCoord-middle))*.5+1.; 20 | } 21 | 22 | //side shadow 23 | vec2 delta = abs(fragCoord-middle)*c*2.; 24 | float sdis = max(delta.x,delta.y); 25 | if(sdis>.9){ 26 | color *= .8; 27 | } 28 | 29 | fragColor = vec4(color,1.0); 30 | } 31 | 32 | void main() { 33 | mainImage(gl_FragColor, texCoord*iResolution.xy); 34 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/lichtenstein_esque.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform float iGlobalTime; 5 | uniform sampler2D iChannel0; 6 | varying vec2 texCoord; 7 | 8 | // Size of the quad in pixels 9 | const float size = 15.0; 10 | 11 | // Radius of the circle 12 | const float radius = size * 0.5; 13 | 14 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 15 | { 16 | // Current quad in pixels 17 | vec2 quadPos = floor(fragCoord.xy / size) * size; 18 | // Normalized quad position 19 | vec2 quad = quadPos/iResolution.xy; 20 | // Center of the quad 21 | vec2 quadCenter = (quadPos + size/2.0); 22 | // Distance to quad center 23 | float dist = length(quadCenter - fragCoord.xy); 24 | 25 | vec4 texel = texture2D(iChannel0, quad); 26 | if (dist > radius) 27 | { 28 | fragColor = vec4(0.25); 29 | } 30 | else 31 | { 32 | fragColor = texel; 33 | } 34 | } 35 | 36 | 37 | void main() { 38 | mainImage(gl_FragColor, texCoord*iResolution.xy); 39 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/voronoi.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform int iFrame; 4 | uniform vec3 iResolution; 5 | uniform vec3 iChannelResolution[2]; 6 | uniform float iGlobalTime; 7 | uniform sampler2D iChannel0; 8 | uniform sampler2D iChannel1; 9 | varying vec2 texCoord; 10 | 11 | 12 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 13 | { 14 | vec2 uv = fragCoord.xy / iResolution.xy; 15 | 16 | #if 0 // debug feature extraction 17 | 18 | fragColor = texture2D(iChannel1, uv).wwww; 19 | 20 | #else 21 | 22 | vec4 cell = texture2D(iChannel0, uv); 23 | vec2 cell_uv = cell.xy; 24 | vec4 video = texture2D(iChannel1, cell_uv); 25 | vec2 dcell = cell_uv * iChannelResolution[0].xy - fragCoord.xy; 26 | float len = length(dcell); 27 | vec3 color = video.xyz * (.9 + len*.005); 28 | fragColor = vec4(color, 1.); 29 | 30 | #endif 31 | } 32 | 33 | void main() { 34 | mainImage(gl_FragColor, texCoord*iResolution.xy); 35 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/enums/MediaQuality.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.enums 2 | 3 | import androidx.annotation.IntDef 4 | 5 | /** 6 | * Media quality 7 | * 8 | * @author [WngShhng](mailto:shouheng2015@gmail.com) 9 | * @version 2019-12-28 16:30 10 | */ 11 | @IntDef(value = [MediaQuality.QUALITY_AUTO, 12 | MediaQuality.QUALITY_LOWEST, 13 | MediaQuality.QUALITY_LOW, 14 | MediaQuality.QUALITY_MEDIUM, 15 | MediaQuality.QUALITY_HIGH, 16 | MediaQuality.QUALITY_HIGHEST]) 17 | @kotlin.annotation.Retention(AnnotationRetention.SOURCE) 18 | annotation class MediaQuality { 19 | companion object { 20 | /** Auto */ 21 | const val QUALITY_AUTO = 0 22 | /** Lowest quality */ 23 | const val QUALITY_LOWEST = 1 24 | /** Low quality */ 25 | const val QUALITY_LOW = 2 26 | /** Medium quality */ 27 | const val QUALITY_MEDIUM = 3 28 | /** High quality */ 29 | const val QUALITY_HIGH = 4 30 | /** Highest quality */ 31 | const val QUALITY_HIGHEST = 5 32 | } 33 | } -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/MappingFilter.java: -------------------------------------------------------------------------------- 1 | 2 | package me.shouheng.icamerasample.filter; 3 | 4 | import android.content.Context; 5 | import android.opengl.GLES20; 6 | 7 | import me.shouheng.icamerasample.R; 8 | import me.shouheng.icamerasample.render.MyGLUtils; 9 | 10 | public class MappingFilter extends CameraFilter { 11 | private int program; 12 | private int texture2Id; 13 | 14 | public MappingFilter(Context context) { 15 | super(context); 16 | 17 | // Build shaders 18 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.mapping); 19 | 20 | // Load the texture will need for the shader 21 | texture2Id = MyGLUtils.loadTexture(context, R.raw.tex00, new int[2]); 22 | } 23 | 24 | @Override 25 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 26 | setupShaderInputs(program, 27 | new int[]{canvasWidth, canvasHeight}, 28 | new int[]{cameraTexId, texture2Id}, 29 | new int[][]{}); 30 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/RefractionFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | 9 | 10 | public class RefractionFilter extends CameraFilter { 11 | private int program; 12 | private int texture2Id; 13 | 14 | public RefractionFilter(Context context) { 15 | super(context); 16 | 17 | // Build shaders 18 | program = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.refraction); 19 | 20 | // Load the texture will need for the shader 21 | texture2Id = MyGLUtils.loadTexture(context, R.raw.tex11, new int[2]); 22 | } 23 | 24 | @Override 25 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 26 | setupShaderInputs(program, 27 | new int[]{canvasWidth, canvasHeight}, 28 | new int[]{cameraTexId, texture2Id}, 29 | new int[][]{}); 30 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/swirl.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform sampler2D iChannel0; 5 | varying vec2 texCoord; 6 | 7 | const float PI = 3.14159265; 8 | const float rotateRadian = PI/3.0; 9 | const float radiusRatio = 0.8; 10 | const float center = 0.5; 11 | 12 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 13 | { 14 | float radius = min(iResolution.x,iResolution.y)*radiusRatio/2.0; 15 | vec2 texCoord = fragCoord; 16 | vec2 currentUV = texCoord; 17 | currentUV.x *= iResolution.x; 18 | currentUV.y *= iResolution.y; 19 | vec2 centerUV = iResolution.xy * center; 20 | vec2 deltaUV = currentUV - centerUV; 21 | 22 | float deltaR = length(deltaUV); 23 | float beta = atan(deltaUV.y, deltaUV.x) + rotateRadian * 2.0 * (-(deltaR/radius)*(deltaR/radius) + 1.0); 24 | 25 | vec2 dstUV = currentUV; 26 | if(deltaR <= radius){ 27 | dstUV = centerUV + deltaR*vec2(cos(beta), sin(beta)); 28 | } 29 | dstUV.x /=iResolution.x; 30 | dstUV.y /=iResolution.y; 31 | fragColor = texture2D(iChannel0, dstUV); 32 | } 33 | 34 | void main() { 35 | mainImage(gl_FragColor, texCoord); 36 | } 37 | -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/preview/impl/BaseCameraPreview.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.preview.impl 2 | 3 | import me.shouheng.icamera.config.size.Size 4 | import me.shouheng.icamera.preview.CameraPreview 5 | import me.shouheng.icamera.preview.CameraPreviewCallback 6 | 7 | /** 8 | * Base camera preview. 9 | * 10 | * @author WngShhng (shouheng2015@gmail.com) 11 | * @version 2019/4/13 22:53 12 | */ 13 | abstract class BaseCameraPreview protected constructor() : CameraPreview { 14 | 15 | private var width = 0 16 | private var height = 0 17 | private var cameraPreviewCallback: CameraPreviewCallback? = null 18 | 19 | override fun setCameraPreviewCallback(cameraPreviewCallback: CameraPreviewCallback?) { 20 | this.cameraPreviewCallback = cameraPreviewCallback 21 | } 22 | 23 | protected fun notifyPreviewAvailable() { 24 | cameraPreviewCallback?.onAvailable(this) 25 | } 26 | 27 | override val isAvailable: Boolean 28 | get() = width > 0 && height > 0 29 | 30 | override val size: Size 31 | get() = Size.of(width, height) 32 | 33 | protected fun setSize(width: Int, height: Int) { 34 | this.width = width 35 | this.height = height 36 | } 37 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/em_interference.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform float iGlobalTime; 5 | uniform sampler2D iChannel0; 6 | varying vec2 texCoord; 7 | 8 | float rng2(vec2 seed) 9 | { 10 | return fract(sin(dot(seed * floor(iGlobalTime * 12.), vec2(127.1,311.7))) * 43758.5453123); 11 | } 12 | 13 | float rng(float seed) 14 | { 15 | return rng2(vec2(seed, 1.0)); 16 | } 17 | 18 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 19 | { 20 | vec2 uv = fragCoord.xy; 21 | vec2 blockS = floor(uv * vec2(24., 9.)); 22 | vec2 blockL = floor(uv * vec2(8., 4.)); 23 | 24 | float r = rng2(uv); 25 | vec3 noise = (vec3(r, 1. - r, r / 2. + 0.5) * 1.0 - 2.0) * 0.08; 26 | 27 | float lineNoise = pow(rng2(blockS), 8.0) * pow(rng2(blockL), 3.0) - pow(rng(7.2341), 17.0) * 2.; 28 | 29 | vec4 col1 = texture2D(iChannel0, uv); 30 | vec4 col2 = texture2D(iChannel0, uv + vec2(lineNoise * 0.05 * rng(5.0), 0)); 31 | vec4 col3 = texture2D(iChannel0, uv - vec2(lineNoise * 0.05 * rng(31.0), 0)); 32 | 33 | fragColor = vec4(vec3(col1.x, col2.y, col3.z) + noise, 1.0); 34 | } 35 | 36 | void main() { 37 | mainImage(gl_FragColor, texCoord); 38 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/config/creator/impl/CameraPreviewCreatorImpl.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.config.creator.impl 2 | 3 | import android.content.Context 4 | import android.os.Build 5 | import android.view.ViewGroup 6 | import me.shouheng.icamera.config.creator.CameraPreviewCreator 7 | import me.shouheng.icamera.preview.CameraPreview 8 | import me.shouheng.icamera.preview.impl.SurfacePreview 9 | import me.shouheng.icamera.preview.impl.TexturePreview 10 | 11 | /** 12 | * Default creator for [CameraPreview], will decide witch to use 13 | * according to build version. 14 | * 15 | * @author WngShhng (shouheng2015@gmail.com) 16 | * @version 2019/4/13 22:56 17 | */ 18 | class CameraPreviewCreatorImpl : CameraPreviewCreator { 19 | /** 20 | * The default implementation for [CameraPreview]. 21 | * If the app version >= 14, [android.view.TextureView] will be used, 22 | * else [android.view.SurfaceView] will be used. 23 | * 24 | * @param context the context to create the preview view. 25 | * @param parent the parent view of the preview. 26 | * @return CameraPreview object. 27 | */ 28 | override fun create( 29 | context: Context, 30 | parent: ViewGroup 31 | ): CameraPreview { 32 | return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 33 | TexturePreview(context, parent) 34 | } else SurfacePreview(context, parent) 35 | } 36 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/config/creator/impl/CameraManagerCreatorImpl.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.config.creator.impl 2 | 3 | import android.content.Context 4 | import android.os.Build 5 | import me.shouheng.icamera.config.creator.CameraManagerCreator 6 | import me.shouheng.icamera.manager.CameraManager 7 | import me.shouheng.icamera.manager.impl.Camera1Manager 8 | import me.shouheng.icamera.manager.impl.Camera2Manager 9 | import me.shouheng.icamera.preview.CameraPreview 10 | import me.shouheng.icamera.util.CameraHelper.hasCamera2 11 | 12 | /** 13 | * Default camera manager creator implementation. 14 | * 15 | * @author WngShhng (shouheng2015@gmail.com) 16 | * @version 2019/4/13 22:56 17 | */ 18 | class CameraManagerCreatorImpl : CameraManagerCreator { 19 | /** 20 | * The default implementation for [CameraManager]. 21 | * If the app version >= 21, the [android.hardware.camera2.CameraDevice] will be used, 22 | * else the [android.hardware.Camera] will be used. 23 | * 24 | * @param context context 25 | * @param cameraPreview the [CameraPreview] 26 | * @return CameraManager object. 27 | */ 28 | override fun create( 29 | context: Context, 30 | cameraPreview: CameraPreview 31 | ): CameraManager { 32 | return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && hasCamera2(context)) { 33 | Camera2Manager(cameraPreview) 34 | } else Camera1Manager(cameraPreview) 35 | } 36 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/noise_warp.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform float iGlobalTime; 5 | uniform sampler2D iChannel0; 6 | varying vec2 texCoord; 7 | 8 | float mod289(float x) 9 | { 10 | return x - floor(x * (1.0 / 289.0)) * 289.0; 11 | } 12 | 13 | vec4 mod289(vec4 x) 14 | { 15 | return x - floor(x * (1.0 / 289.0)) * 289.0; 16 | } 17 | 18 | vec4 perm(vec4 x) 19 | { 20 | return mod289(((x * 34.0) + 1.0) * x); 21 | } 22 | 23 | float noise3d(vec3 p) 24 | { 25 | vec3 a = floor(p); 26 | vec3 d = p - a; 27 | d = d * d * (3.0 - 2.0 * d); 28 | 29 | vec4 b = a.xxyy + vec4(0.0, 1.0, 0.0, 1.0); 30 | vec4 k1 = perm(b.xyxy); 31 | vec4 k2 = perm(k1.xyxy + b.zzww); 32 | 33 | vec4 c = k2 + a.zzzz; 34 | vec4 k3 = perm(c); 35 | vec4 k4 = perm(c + 1.0); 36 | 37 | vec4 o1 = fract(k3 * (1.0 / 41.0)); 38 | vec4 o2 = fract(k4 * (1.0 / 41.0)); 39 | 40 | vec4 o3 = o2 * d.z + o1 * (1.0 - d.z); 41 | vec2 o4 = o3.yw * d.x + o3.xz * (1.0 - d.x); 42 | 43 | return o4.y * d.y + o4.x * (1.0 - d.y); 44 | } 45 | 46 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 47 | { 48 | vec2 uv = fragCoord.xy; 49 | float v1 = noise3d(vec3(uv * 10.0, 0.0)); 50 | float v2 = noise3d(vec3(uv * 10.0, 1.0)); 51 | 52 | vec4 color = texture2D(iChannel0, uv + vec2(v1, v2) * 0.1); 53 | fragColor = color; 54 | } 55 | 56 | void main() { 57 | mainImage(gl_FragColor, texCoord); 58 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/cracked.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform float iGlobalTime; 5 | uniform sampler2D iChannel0; 6 | varying vec2 texCoord; 7 | 8 | float rnd(vec2 s) 9 | { 10 | return 1.-2.*fract(sin(s.x*253.13+s.y*341.41)*589.19); 11 | } 12 | 13 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 14 | { 15 | vec2 p=(fragCoord.xy*2.-iResolution.xy)/iResolution.x; 16 | 17 | vec2 v=vec2(1E3); 18 | vec2 v2=vec2(1E4); 19 | vec2 center=vec2(.1,-.5); 20 | for(int c=0;c<30;c++) 21 | { 22 | float angle=floor(rnd(vec2(float(c),387.44))*16.)*3.1415*.4-.5; 23 | float dist=pow(rnd(vec2(float(c),78.21)),2.)*.5; 24 | vec2 vc=vec2(center.x+cos(angle)*dist+rnd(vec2(float(c),349.3))*7E-3, 25 | center.y+sin(angle)*dist+rnd(vec2(float(c),912.7))*7E-3); 26 | if(length(vc-p) 2 | 3 | 36 | -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.21' 3 | ext.kotlin_coroutines_version = '1.3.3' 4 | repositories { 5 | google() 6 | jcenter() 7 | mavenCentral() 8 | maven { url "https://jitpack.io" } 9 | maven { url "https://maven.google.com/" } 10 | } 11 | dependencies { 12 | classpath 'com.android.tools.build:gradle:3.5.1' 13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 14 | classpath 'com.novoda:bintray-release:0.9.1' 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | google() 21 | jcenter() 22 | mavenCentral() 23 | maven { url "https://jitpack.io" } 24 | maven { url "https://maven.google.com/" } 25 | maven { url "https://dl.bintray.com/easymark/Android" } 26 | } 27 | tasks.withType(Javadoc) { 28 | options.addStringOption('Xdoclint:none', '-quiet') 29 | options.addStringOption('encoding', 'UTF-8') 30 | } 31 | tasks.withType(Javadoc) { 32 | options.addStringOption('Xdoclint:none', '-quiet') 33 | options.addStringOption('encoding', 'UTF-8') 34 | } 35 | } 36 | 37 | task clean(type: Delete) { 38 | delete rootProject.buildDir 39 | } 40 | 41 | tasks.withType(JavaCompile) { 42 | options.encoding = "UTF-8" 43 | } 44 | 45 | ext { 46 | compileSdkVersion = 28 47 | buildToolsVersion = '28.0.0' 48 | targetSdkVersion = compileSdkVersion 49 | minSdkVersion = 14 50 | supportLibVersion = '28.0.0' 51 | androidUtilsVersion = '1.3.6' 52 | publishVersion = "0.3.0-beta" 53 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/voronoi_buf_a.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform int iFrame; 4 | uniform vec3 iResolution; 5 | uniform vec3 iChannelResolution[2]; 6 | uniform float iGlobalTime; 7 | uniform sampler2D iChannel0; 8 | uniform sampler2D iChannel1; 9 | varying vec2 texCoord; 10 | 11 | // A super simple video source with feature detection 12 | 13 | float grayScale(vec4 c) { return c.x*.29 + c.y*.58 + c.z*.13; } 14 | 15 | //============================================================ 16 | vec4 GenerateSeed (in vec2 fragCoord) 17 | { 18 | vec2 uv = fragCoord / iResolution.xy; 19 | vec3 dataStep = vec3( vec2(1.) / iChannelResolution[0].xy, 0.); 20 | 21 | vec4 fragColor = texture2D( iChannel0, uv ); 22 | 23 | float d = grayScale(fragColor); 24 | float dL = grayScale(texture2D( iChannel0, uv - dataStep.xz )); 25 | float dR = grayScale(texture2D( iChannel0, uv + dataStep.xz )); 26 | float dU = grayScale(texture2D( iChannel0, uv - dataStep.zy )); 27 | float dD = grayScale(texture2D( iChannel0, uv + dataStep.zy )); 28 | float w = float( d*0.99 > max(max(dL, dR), max(dU, dD)) ); 29 | 30 | w = max(w, texture2D( iChannel1, uv ).w*.9); // get some from previous frame 31 | 32 | fragColor.w = w; 33 | 34 | return fragColor; 35 | } 36 | 37 | //============================================================ 38 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 39 | { 40 | fragColor = GenerateSeed(fragCoord); 41 | } 42 | 43 | 44 | void main() { 45 | mainImage(gl_FragColor, texCoord*iResolution.xy); 46 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/util/XLog.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.util 2 | 3 | import java.util.concurrent.CopyOnWriteArrayList 4 | 5 | /** 6 | * A simple logger to use in library. 7 | * 8 | * @author WngShhng (shouheng2015@gmail.com) 9 | * @version 2019/4/14 9:33 10 | */ 11 | object XLog { 12 | 13 | private var isDebug = false 14 | private var watchers: CopyOnWriteArrayList = CopyOnWriteArrayList() 15 | 16 | fun v(tag: String, msg: String?) { 17 | watchers.forEach { it.onLog(LogLevel.V, tag, msg) } 18 | } 19 | 20 | @JvmStatic 21 | fun d(tag: String, msg: String?) { 22 | watchers.forEach { it.onLog(LogLevel.D, tag, msg) } 23 | } 24 | 25 | @JvmStatic 26 | fun i(tag: String, msg: String?) { 27 | watchers.forEach { it.onLog(LogLevel.I, tag, msg) } 28 | } 29 | 30 | @JvmStatic 31 | fun w(tag: String, msg: String?) { 32 | watchers.forEach { it.onLog(LogLevel.W, tag, msg) } 33 | } 34 | 35 | @JvmStatic 36 | fun e(tag: String, msg: String?) { 37 | watchers.forEach { it.onLog(LogLevel.E, tag, msg) } 38 | } 39 | 40 | @JvmStatic 41 | fun setDebug(debug: Boolean) { 42 | isDebug = debug 43 | } 44 | 45 | @JvmStatic 46 | fun addLogWatcher(watcher: LogWatcher) { 47 | if (!watchers.contains(watcher)) { 48 | watchers.add(watcher) 49 | } 50 | } 51 | 52 | @JvmStatic 53 | fun removeLogWatcher(watcher: LogWatcher) { 54 | watchers.remove(watcher) 55 | } 56 | } 57 | 58 | interface LogWatcher { 59 | fun onLog(level: LogLevel, tag: String, msg: String?) 60 | } 61 | 62 | enum class LogLevel { 63 | V, D, I, W, E 64 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/tile_mosaic.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform sampler2D iChannel0; 5 | varying vec2 texCoord; 6 | 7 | vec2 tile_num = vec2(40.0, 20.0); 8 | 9 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 10 | { 11 | const float minTileSize = 1.0; 12 | const float maxTileSize = 32.0; 13 | const float textureSamplesCount = 3.0; 14 | const float textureEdgeOffset = 0.005; 15 | const float borderSize = 1.0; 16 | const float size = 0.5; 17 | 18 | float tileSize = minTileSize + floor(size * (maxTileSize - minTileSize)); 19 | tileSize += mod(tileSize, 2.0); 20 | vec2 tileNumber = floor(fragCoord / tileSize); 21 | 22 | vec4 accumulator = vec4(0.0); 23 | for (float y = 0.0; y < textureSamplesCount; ++y) 24 | { 25 | for (float x = 0.0; x < textureSamplesCount; ++x) 26 | { 27 | vec2 textureCoordinates = (tileNumber + vec2((x + 0.5)/textureSamplesCount, (y + 0.5)/textureSamplesCount)) * tileSize / iResolution.xy; 28 | textureCoordinates = clamp(textureCoordinates, 0.0 + textureEdgeOffset, 1.0 - textureEdgeOffset); 29 | accumulator += texture2D(iChannel0, textureCoordinates); 30 | } 31 | } 32 | 33 | fragColor = accumulator / vec4(textureSamplesCount * textureSamplesCount); 34 | 35 | vec2 pixelNumber = floor(fragCoord - (tileNumber * tileSize)); 36 | pixelNumber = mod(pixelNumber + borderSize, tileSize); 37 | 38 | float pixelBorder = step(min(pixelNumber.x, pixelNumber.y), borderSize) * step(borderSize * 2.0 + 1.0, tileSize); 39 | //float pixelBorder = step(pixelNumber.x, borderSize) * step(pixelNumber.y, borderSize) * step(borderSize * 2.0 + 1.0, tileSize); 40 | 41 | fragColor *= pow(fragColor, vec4(pixelBorder)); 42 | } 43 | 44 | void main() { 45 | mainImage(gl_FragColor, texCoord.xy*iResolution.xy); 46 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/polygonization.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform float iGlobalTime; 5 | uniform sampler2D iChannel0; 6 | varying vec2 texCoord; 7 | 8 | vec2 hash2( vec2 p ) 9 | { 10 | // procedural white noise 11 | return fract(sin(vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3))))*43758.5453); 12 | } 13 | 14 | vec2 voronoi( in vec2 x ) 15 | { 16 | vec2 n = floor(x); 17 | vec2 f = fract(x); 18 | 19 | //---------------------------------- 20 | // regular voronoi 21 | //---------------------------------- 22 | vec2 mg, mr; 23 | 24 | float md = 8.0; 25 | for( int j=-1; j<=1; j++ ) 26 | for( int i=-1; i<=1; i++ ) 27 | { 28 | vec2 g = vec2(float(i),float(j)); 29 | vec2 o = hash2( n + g ); 30 | vec2 r = g + o - f; 31 | float d = dot(r,r); 32 | 33 | if( d 2 | iCamera 3 | 4 | Launch iCamera 5 | PICK YOUR CAMERA OPTION: 6 | Camera1 Only 7 | Camera2 Only 8 | According to Platform 9 | PICK YOUR CAMERA PREVIEW OPTION: 10 | TextureView Only 11 | SurfaceView Only 12 | According to Platform 13 | About iCamera 14 | Sorry, Crash happened! 15 | 16 | Max Video Duration (s): 17 | Camera Configuration 18 | Shutter 19 | Auto Focus 20 | Flash 21 | Touch Zoom 22 | Touch Focus 23 | Preview Sizes 24 | Picture Sizes 25 | Video Sizes 26 | Switch Front/End 27 | 28 | Video 29 | Picture 30 | 31 | Too dark, open the flash? 32 | 33 | -------------------------------------------------------------------------------- /sample/app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /sample/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 13 | 14 | 24 | 25 | 32 | 33 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/voronoi_buf_b.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform int iFrame; 4 | uniform vec3 iResolution; 5 | uniform vec3 iChannelResolution[2]; 6 | uniform float iGlobalTime; 7 | uniform sampler2D iChannel0; 8 | uniform sampler2D iChannel1; 9 | varying vec2 texCoord; 10 | 11 | 12 | // how many JFA steps to do. 2^c_maxSteps is max image size on x and y 13 | const float c_maxSteps = 10.0; 14 | 15 | //============================================================ 16 | vec4 StepJFA (in vec2 fragCoord, in float level) 17 | { 18 | float stepwidth = floor(exp2(c_maxSteps - 1. - level)+0.5); 19 | 20 | float bestDistance = 9999.0; 21 | vec2 bestCoord = vec2(0.0); 22 | 23 | for (int y = -1; y <= 1; ++y) { 24 | for (int x = -1; x <= 1; ++x) { 25 | vec2 sampleCoord = fragCoord + vec2(x,y) * stepwidth; 26 | 27 | vec4 data = texture2D( iChannel0, sampleCoord / iChannelResolution[0].xy); 28 | vec2 seedCoord = data.xy * iChannelResolution[0].xy; 29 | float dist = length(seedCoord - fragCoord); 30 | if ((seedCoord.x != 0.0 || seedCoord.y != 0.0) && dist < bestDistance) 31 | { 32 | bestDistance = dist; 33 | bestCoord = seedCoord; 34 | } 35 | } 36 | } 37 | 38 | return vec4(bestCoord / iChannelResolution[0].xy, 0.0, 0.0); 39 | } 40 | 41 | //============================================================ 42 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 43 | { 44 | float fFrame = float(iFrame); 45 | float level = mod(fFrame,c_maxSteps); 46 | if (level < .5) { 47 | if (texture2D(iChannel1, fragCoord / iResolution.xy).w > .5) 48 | fragColor = vec4(fragCoord / iChannelResolution[0].xy, 0.0, 0.0); 49 | else 50 | fragColor = vec4(0.0); 51 | return; 52 | } 53 | 54 | fragColor = StepJFA(fragCoord, level); 55 | } 56 | 57 | 58 | void main() { 59 | mainImage(gl_FragColor, texCoord*iResolution.xy); 60 | } -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/utils/FileHelper.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.utils 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.net.Uri 6 | import android.os.Build 7 | import android.provider.MediaStore 8 | import androidx.core.content.FileProvider 9 | import me.shouheng.icamerasample.BuildConfig 10 | import me.shouheng.icamerasample.R 11 | import me.shouheng.utils.app.ResUtils 12 | import me.shouheng.utils.stability.L 13 | import me.shouheng.utils.store.FileUtils 14 | import me.shouheng.utils.store.PathUtils 15 | import java.io.File 16 | import java.io.FileNotFoundException 17 | 18 | /** 19 | * @author WngShhng 20 | * @version 2020-08-25 16:21 21 | */ 22 | object FileHelper { 23 | 24 | fun saveImageToGallery(context: Context, file: File, fileName: String) { 25 | try { 26 | MediaStore.Images.Media.insertImage(context.contentResolver, file.absolutePath, fileName, null) 27 | } catch (e: FileNotFoundException) { 28 | L.d("saveImageToGallery: FileNotFoundException MediaStore") 29 | e.printStackTrace() 30 | } 31 | context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, getUriFromFile(context, file))) 32 | } 33 | 34 | fun saveVideoToGallery(context: Context, file: File, fileName: String) { 35 | context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, getUriFromFile(context, file))) 36 | } 37 | 38 | fun getSavedFile(appendix: String): File { 39 | val appDir = File(PathUtils.getExternalPicturesPath(), ResUtils.getString(R.string.app_name)) 40 | FileUtils.createOrExistsDir(appDir.path) 41 | val fileName = "${System.currentTimeMillis()}.${appendix}" 42 | return File(appDir, fileName) 43 | } 44 | 45 | fun getUriFromFile(context: Context, file: File): Uri { 46 | return if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M){ 47 | FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", file); 48 | } else { 49 | Uri.fromFile(file) 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/preview/CameraPreview.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.preview 2 | 3 | import android.graphics.SurfaceTexture 4 | import android.view.Surface 5 | import android.view.SurfaceHolder 6 | import android.view.View 7 | import me.shouheng.icamera.config.size.Size 8 | import me.shouheng.icamera.enums.PreviewViewType 9 | 10 | /** 11 | * The camera preview interface. 12 | * 13 | * @author WngShhng (shouheng2015@gmail.com) 14 | * @version 2019/4/13 22:53 15 | */ 16 | interface CameraPreview { 17 | 18 | /** 19 | * Add callback to the camera preview. 20 | * 21 | * @param cameraPreviewCallback the callback interface. 22 | */ 23 | fun setCameraPreviewCallback(cameraPreviewCallback: CameraPreviewCallback?) 24 | 25 | /** 26 | * Get the surface from this preview that will be used for 27 | * [android.hardware.camera2.CameraDevice] 28 | * 29 | * @return surface 30 | */ 31 | val surface: Surface? 32 | 33 | /** 34 | * Get the preview type the camera preview is based on. 35 | * This will be used to decide which method of [.getSurfaceHolder] 36 | * and [.getSurfaceTexture] will be called. 37 | * 38 | * @return the preview type 39 | * @see PreviewViewType 40 | */ 41 | @get:PreviewViewType 42 | val previewType: Int 43 | 44 | /** 45 | * Get [SurfaceHolder] from [android.view.SurfaceView]. 46 | * 47 | * @return SurfaceHolder object, Might be null if the preview view is 48 | * [android.view.TextureView]. 49 | */ 50 | val surfaceHolder: SurfaceHolder? 51 | 52 | /** 53 | * Get [SurfaceTexture] from [android.view.TextureView]. 54 | * 55 | * @return SurfaceTexture object. Might be null if the preview view is 56 | * [android.view.SurfaceView]. 57 | */ 58 | val surfaceTexture: SurfaceTexture? 59 | 60 | /** 61 | * Is the camera preview available now. 62 | * 63 | * @return true if available 64 | */ 65 | val isAvailable: Boolean 66 | 67 | /** 68 | * Get the size of this camera preview. 69 | * 70 | * @return the size 71 | */ 72 | val size: Size? 73 | 74 | /** 75 | * Get the real view that is displaying the camera data. 76 | * 77 | * @return the view 78 | */ 79 | val view: View? 80 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/config/size/AspectRatio.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.config.size 2 | 3 | import androidx.annotation.IntRange 4 | import me.shouheng.icamera.util.XLog.d 5 | 6 | /** 7 | * Aspect ratio 8 | * 9 | * @author WngShhng (shouheng2015@gmail.com) 10 | * @version 2019/4/13 23:08 11 | */ 12 | class AspectRatio private constructor(val widthRatio: Int, val heightRatio: Int) { 13 | 14 | private var ratio = 0.0 15 | 16 | fun ratio(): Double { 17 | if (ratio == 0.0) { 18 | ratio = heightRatio.toDouble() / widthRatio 19 | } 20 | return ratio 21 | } 22 | 23 | fun inverse(): AspectRatio = of(heightRatio, widthRatio) 24 | 25 | override fun equals(other: Any?): Boolean { 26 | if (this === other) return true 27 | if (other == null || javaClass != other.javaClass) return false 28 | val that = other as AspectRatio 29 | return java.lang.Double.compare(that.ratio(), ratio()) == 0 30 | } 31 | 32 | override fun hashCode(): Int { 33 | val temp = java.lang.Double.doubleToLongBits(ratio()) 34 | return (temp xor (temp ushr 32)).toInt() 35 | } 36 | 37 | override fun toString(): String { 38 | return "AspectRatio{" + 39 | "ratio=" + ratio + 40 | ", widthRatio=" + widthRatio + 41 | ", heightRatio=" + heightRatio + 42 | '}' 43 | } 44 | 45 | companion object { 46 | 47 | fun of(size: Size): AspectRatio = AspectRatio(size.width, size.height) 48 | 49 | @JvmStatic 50 | fun of(@IntRange(from = 1) wr: Int, @IntRange(from = 0) hr: Int): AspectRatio { 51 | return AspectRatio(wr, hr) 52 | } 53 | 54 | fun parse(s: String): AspectRatio { 55 | val position = s.indexOf(':') 56 | require(position != -1) { "Malformed aspect ratio: $s" } 57 | return try { 58 | val x = s.substring(0, position).toInt() 59 | val y = s.substring(position + 1).toInt() 60 | d("AspectRatio", "Parsed aspect ratio from string as $x : $y") 61 | of(x, y) 62 | } catch (e: NumberFormatException) { 63 | throw IllegalArgumentException("Malformed aspect ratio: $s", e) 64 | } 65 | } 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/money_filter.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform float iGlobalTime; 5 | uniform sampler2D iChannel0; 6 | varying vec2 texCoord; 7 | 8 | 9 | // Money filter by Giacomo Preciado 10 | // Based on: "Free Engraved Illustration Effect Action for Photoshop" - http://snip.ly/j0gq 11 | // e-mail: giacomo@kyrie.pe 12 | // website: http://kyrie.pe 13 | 14 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 15 | { 16 | vec2 xy = fragCoord.xy / iResolution.yy; 17 | 18 | float amplitud = 0.03; 19 | float frecuencia = 10.0; 20 | float gris = 1.0; 21 | float divisor = 8.0 / iResolution.y; 22 | float grosorInicial = divisor * 0.2; 23 | 24 | const int kNumPatrones = 6; 25 | 26 | // x: seno del angulo, y: coseno del angulo, z: factor de suavizado 27 | vec3 datosPatron[kNumPatrones]; 28 | datosPatron[0] = vec3(-0.7071, 0.7071, 3.0); // -45 29 | datosPatron[1] = vec3(0.0, 1.0, 0.6); // 0 30 | datosPatron[2] = vec3(0.0, 1.0, 0.5); // 0 31 | datosPatron[3] = vec3(1.0, 0.0, 0.4); // 90 32 | datosPatron[4] = vec3(1.0, 0.0, 0.3); // 90 33 | datosPatron[5] = vec3(0.0, 1.0, 0.2); // 0 34 | 35 | vec4 color = texture2D(iChannel0, vec2(fragCoord.x / iResolution.x, xy.y)); 36 | fragColor = color; 37 | 38 | for(int i = 0; i < kNumPatrones; i++) 39 | { 40 | float coseno = datosPatron[i].x; 41 | float seno = datosPatron[i].y; 42 | 43 | vec2 punto = vec2( 44 | xy.x * coseno - xy.y * seno, 45 | xy.x * seno + xy.y * coseno 46 | ); 47 | 48 | float grosor = grosorInicial * float(i + 1); 49 | float dist = mod(punto.y + grosor * 0.5 - sin(punto.x * frecuencia) * amplitud, divisor); 50 | float brillo = 0.3 * color.r + 0.4 * color.g + 0.3 * color.b; 51 | 52 | if(dist < grosor && brillo < 0.75 - 0.12 * float(i)) 53 | { 54 | // Suavizado 55 | float k = datosPatron[i].z; 56 | float x = (grosor - dist) / grosor; 57 | float fx = abs((x - 0.5) / k) - (0.5 - k) / k; 58 | gris = min(fx, gris); 59 | } 60 | } 61 | 62 | fragColor = vec4(gris, gris, gris, 1.0); 63 | } 64 | 65 | void main() { 66 | mainImage(gl_FragColor, texCoord*iResolution.xy); 67 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/enums/PreviewAdjustType.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.enums 2 | 3 | import androidx.annotation.IntDef 4 | 5 | /** 6 | * Camera preview adjust type, will be used to decide how 7 | * the imagery is displayed when the preview view size diffs 8 | * from the imagery size. 9 | * 10 | * @author [WngShhng](mailto:shouheng2015@gmail.com) 11 | * @version 2019-12-28 11:55 12 | */ 13 | @IntDef( 14 | PreviewAdjustType.NONE, 15 | PreviewAdjustType.WIDTH_FIRST, 16 | PreviewAdjustType.HEIGHT_FIRST, 17 | PreviewAdjustType.SMALLER_FIRST, 18 | PreviewAdjustType.LARGER_FIRST 19 | ) 20 | @kotlin.annotation.Retention(AnnotationRetention.SOURCE) 21 | annotation class PreviewAdjustType { 22 | companion object { 23 | /** The imagery will be stretched to fit the view */ 24 | const val NONE = 0 25 | 26 | /** 27 | * Use the width of view, 28 | * the height will be stretched to meet the aspect ratio. 29 | * 30 | * Example: 31 | * 32 | * +-------------+ 33 | * | | 34 | * |/////////////| 35 | * |/////////////| 36 | * |// image //| 37 | * |/////////////| 38 | * |/////////////| 39 | * | | 40 | * +-------------+ */ 41 | const val WIDTH_FIRST = 1 42 | 43 | /** 44 | * Use the height of view, 45 | * the width will be stretched to meet the aspect ratio. 46 | * 47 | * Example: 48 | * 49 | * +-------------+ 50 | * | ///////// | 51 | * | ///////// | 52 | * | ///////// | 53 | * | / image / | 54 | * | ///////// | 55 | * | ///////// | 56 | * | ///////// | 57 | * +-------------+ */ 58 | const val HEIGHT_FIRST = 2 59 | 60 | /** 61 | * Use the smaller side between height and width, 62 | * another will be stretched to meet the aspect ratio. 63 | * 64 | * @see .WIDTH_FIRST 65 | * 66 | * @see .HEIGHT_FIRST 67 | */ 68 | const val SMALLER_FIRST = 3 69 | 70 | /** 71 | * Use the larger side between height and width, 72 | * another will be stretched to meet the aspect ratio. 73 | * 74 | * @see .WIDTH_FIRST 75 | * 76 | * @see .HEIGHT_FIRST 77 | */ 78 | const val LARGER_FIRST = 4 79 | } 80 | } -------------------------------------------------------------------------------- /sample/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-kapt' 4 | apply plugin: 'kotlin-android-extensions' 5 | 6 | android { 7 | compileSdkVersion rootProject.ext.compileSdkVersion 8 | defaultConfig { 9 | applicationId "me.shouheng.icamerasample" 10 | minSdkVersion rootProject.ext.minSdkVersion 11 | targetSdkVersion rootProject.ext.targetSdkVersion 12 | versionCode 1 13 | versionName "1.0" 14 | testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' 15 | } 16 | signingConfigs { 17 | release { 18 | keyAlias "${_keyAlias}" 19 | storeFile file("${_storeFile}") 20 | storePassword "${_storePassword}" 21 | keyPassword "${_keyPassword}" 22 | } 23 | } 24 | buildTypes { 25 | release { 26 | signingConfig signingConfigs.release 27 | minifyEnabled false 28 | shrinkResources false // enable shrink resources 29 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 30 | } 31 | applicationVariants.all { variant -> 32 | variant.outputs.all { output -> 33 | outputFileName = defaultConfig.applicationId + "-" + variant.baseName + "-" + defaultConfig.versionName + "-" + defaultConfig.versionCode + ".apk"; 34 | } 35 | } 36 | } 37 | // use data binding 38 | dataBinding { 39 | enabled = true 40 | } 41 | android { 42 | lintOptions { 43 | abortOnError false 44 | } 45 | } 46 | } 47 | 48 | dependencies { 49 | implementation fileTree(dir: 'libs', include: ['*.jar']) 50 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 51 | implementation 'androidx.appcompat:appcompat:1.0.0' 52 | implementation 'com.google.android.material:material:1.0.0' 53 | implementation 'me.shouheng.vmlib:vmlib-core:1.5.9' 54 | implementation ('me.shouheng.ui:uix-core:1.6.20') { 55 | exclude group: "me.shouheng.icamera" 56 | } 57 | implementation 'me.shouheng.utils:utils-ktx:2.1.5' 58 | // leakcanarye 59 | debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.2' 60 | releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.1' 61 | implementation 'com.github.Shouheng88:icamera:0.2.0-beta' 62 | // implementation project(path: ':icamera') 63 | } 64 | -------------------------------------------------------------------------------- /sample/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /sample/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 24 | 25 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 40 | 41 | 46 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/listener/DisplayOrientationDetector.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.listener 2 | 3 | import android.content.Context 4 | import android.util.SparseIntArray 5 | import android.view.Display 6 | import android.view.OrientationEventListener 7 | import android.view.Surface 8 | 9 | /** 10 | * @author WngShhng (shouheng2015@gmail.com) 11 | * @version 2019/4/17 22:26 12 | */ 13 | abstract class DisplayOrientationDetector protected constructor(context: Context?) { 14 | private val orientationEventListener: OrientationEventListener 15 | 16 | companion object { 17 | private val DISPLAY_ORIENTATIONS = SparseIntArray() 18 | 19 | init { 20 | DISPLAY_ORIENTATIONS.put(Surface.ROTATION_0, 0) 21 | DISPLAY_ORIENTATIONS.put(Surface.ROTATION_90, 90) 22 | DISPLAY_ORIENTATIONS.put(Surface.ROTATION_180, 180) 23 | DISPLAY_ORIENTATIONS.put(Surface.ROTATION_270, 270) 24 | } 25 | } 26 | 27 | private var display: Display? = null 28 | 29 | var lastKnownDisplayOrientation = 0 30 | private set 31 | 32 | fun enable(display: Display?) { 33 | this.display = display 34 | orientationEventListener.enable() 35 | display?.let { 36 | // Immediately dispatch the first callback 37 | dispatchOnDisplayOrientationChanged(DISPLAY_ORIENTATIONS[it.rotation]) 38 | } 39 | } 40 | 41 | fun disable() { 42 | orientationEventListener.disable() 43 | display = null 44 | } 45 | 46 | private fun dispatchOnDisplayOrientationChanged(displayOrientation: Int) { 47 | lastKnownDisplayOrientation = displayOrientation 48 | onDisplayOrientationChanged(displayOrientation) 49 | } 50 | 51 | /** 52 | * Called when display orientation is changed. 53 | * 54 | * @param displayOrientation One of 0, 90, 180, and 270. 55 | */ 56 | abstract fun onDisplayOrientationChanged(displayOrientation: Int) 57 | 58 | init { 59 | orientationEventListener = object : OrientationEventListener(context) { 60 | private var mLastKnownRotation = -1 61 | override fun onOrientationChanged(orientation: Int) { 62 | if (orientation == ORIENTATION_UNKNOWN || display == null) { 63 | return 64 | } 65 | val rotation = display!!.rotation 66 | if (mLastKnownRotation != rotation) { 67 | mLastKnownRotation = rotation 68 | dispatchOnDisplayOrientationChanged(DISPLAY_ORIENTATIONS[rotation]) 69 | } 70 | } 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /icamera/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | 34 | 35 | 36 | 38 | 39 | 40 | 41 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/render/RenderBuffer.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.render; 2 | 3 | import android.opengl.GLES20; 4 | 5 | import java.nio.ByteBuffer; 6 | import java.nio.ByteOrder; 7 | import java.nio.IntBuffer; 8 | 9 | import javax.microedition.khronos.opengles.GL10; 10 | 11 | public class RenderBuffer { 12 | private int texId = 0; 13 | private int activeTexUnit = 0; 14 | private int renderBufferId = 0; 15 | private int frameBufferId = 0; 16 | 17 | private int width, height; 18 | 19 | public RenderBuffer(int width, int height, int activeTexUnit) { 20 | this.width = width; 21 | this.height = height; 22 | this.activeTexUnit = activeTexUnit; 23 | int[] genbuf = new int[1]; 24 | 25 | // Generate and bind 2d texture 26 | GLES20.glActiveTexture(activeTexUnit); 27 | texId = MyGLUtils.genTexture(); 28 | IntBuffer texBuffer = 29 | ByteBuffer.allocateDirect(width * height * 4).order(ByteOrder.nativeOrder()).asIntBuffer(); 30 | GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, texBuffer); 31 | 32 | GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); 33 | GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); 34 | GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE); 35 | GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE); 36 | 37 | // Generate frame buffer 38 | GLES20.glGenFramebuffers(1, genbuf, 0); 39 | frameBufferId = genbuf[0]; 40 | // Bind frame buffer 41 | GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBufferId); 42 | 43 | // Generate render buffer 44 | GLES20.glGenRenderbuffers(1, genbuf, 0); 45 | renderBufferId = genbuf[0]; 46 | // Bind render buffer 47 | GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, renderBufferId); 48 | GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, width, height); 49 | 50 | unbind(); 51 | } 52 | 53 | public int getTexId() { 54 | return texId; 55 | } 56 | 57 | public int getWidth() { 58 | return width; 59 | } 60 | 61 | public int getHeight() { 62 | return height; 63 | } 64 | 65 | public int getActiveTexUnit() { 66 | return activeTexUnit; 67 | } 68 | 69 | public void bind() { 70 | GLES20.glViewport(0, 0, width, height); 71 | 72 | GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBufferId); 73 | GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, 74 | GLES20.GL_TEXTURE_2D, texId, 0); 75 | GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, 76 | GLES20.GL_RENDERBUFFER, renderBufferId); 77 | } 78 | 79 | public void unbind() { 80 | GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /sample/.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | 39 | 40 | 44 | 45 | 49 | 50 | 54 | 55 | 59 | 60 | -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/manager/CameraManager.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.manager 2 | 3 | import android.content.Context 4 | import me.shouheng.icamera.config.size.AspectRatio 5 | import me.shouheng.icamera.config.size.Size 6 | import me.shouheng.icamera.config.size.SizeMap 7 | import me.shouheng.icamera.enums.* 8 | import me.shouheng.icamera.listener.* 9 | import java.io.File 10 | 11 | /** 12 | * The camera manager interface. 13 | * 14 | * @author WngShhng (shouheng2015@gmail.com) 15 | * @version 2019/4/13 22:49 16 | */ 17 | interface CameraManager { 18 | 19 | /** Initialize camera manager. */ 20 | fun initialize(context: Context) 21 | 22 | /** Open camera. */ 23 | fun openCamera(cameraOpenListener: CameraOpenListener?) 24 | 25 | /** Is camera opened */ 26 | val isCameraOpened: Boolean 27 | 28 | /** Get current camera face */ 29 | @get:CameraFace 30 | var cameraFace: Int 31 | 32 | /** Switch camera face */ 33 | fun switchCamera(@CameraFace cameraFace: Int) 34 | 35 | /** Get current media type */ 36 | @get:MediaType 37 | var mediaType: Int 38 | 39 | /** Is voice enabled */ 40 | var isVoiceEnable: Boolean 41 | 42 | /** Is current auto focus */ 43 | var isAutoFocus: Boolean 44 | 45 | /** Get current flash mode */ 46 | @get:FlashMode 47 | var flashMode: Int 48 | 49 | /** Current zoom */ 50 | var zoom: Float 51 | 52 | /** Get max zoom */ 53 | fun getMaxZoom(): Float 54 | 55 | /** Set desired size */ 56 | fun setExpectSize(expectSize: Size) 57 | 58 | /** Sed desired aspect ratio.*/ 59 | fun setExpectAspectRatio(expectAspectRatio: AspectRatio) 60 | 61 | /** Set desired media quality */ 62 | fun setMediaQuality(@MediaQuality mediaQuality: Int) 63 | 64 | /** Get current size for usage. */ 65 | fun getSize(@CameraSizeFor sizeFor: Int): Size? 66 | 67 | /** Get sizes map from aspect ratio to sizes.*/ 68 | fun getSizes(@CameraSizeFor sizeFor: Int): SizeMap? 69 | 70 | /** Get current aspect ratio of preview, picture or video. */ 71 | fun getAspectRatio(@CameraSizeFor sizeFor: Int): AspectRatio? 72 | 73 | /** Set display orientation */ 74 | var displayOrientation: Int 75 | 76 | /** Add camera size change callback */ 77 | fun addCameraSizeListener(cameraSizeListener: CameraSizeListener) 78 | 79 | /** Set the camera preview listener */ 80 | fun setCameraPreviewListener(cameraPreviewListener: CameraPreviewListener) 81 | 82 | /** Take a picture */ 83 | fun takePicture(fileToSave: File, cameraPhotoListener: CameraPhotoListener?) 84 | 85 | /** Get max video file size */ 86 | var videoFileSize: Long 87 | 88 | /** Get max video duration */ 89 | var videoDuration: Int 90 | 91 | /** Start video record */ 92 | fun startVideoRecord(file: File, cameraVideoListener: CameraVideoListener?) 93 | 94 | /** Stop video record */ 95 | fun stopVideoRecord() 96 | 97 | /** Resume preview */ 98 | fun resumePreview() 99 | 100 | /** Close camera */ 101 | fun closeCamera(cameraCloseListener: CameraCloseListener?) 102 | 103 | /** Release camera, destroy thread etc. */ 104 | fun releaseCamera() 105 | } -------------------------------------------------------------------------------- /TESTLIST.md: -------------------------------------------------------------------------------- 1 | # The Test List of iCamera 2 | 3 | ## 1、Camera1 with TextureView 4 | 5 | |No|Item|OnePlus6| 6 | |:-----:|:-----|:-----:| 7 | |1|Open|Pass| 8 | |2|Close|Pass| 9 | |3|Resume|Watch| 10 | |4|Flash|Pass| 11 | ||Flash On|Pass| 12 | ||Flash Off|Pass| 13 | ||Flash Auto|Pass| 14 | |5|Shutter Enable|Pass| 15 | ||Shutter Disable|Pass| 16 | |6|Rotation|Pass| 17 | |7|Change size|Watch| 18 | |8|Capture with rear camera (voidce)|Pass| 19 | |9|Capture with front camera (voidce)|Pass| 20 | |10|Record with rear canera (voidce)|Pass| 21 | |11|Recond with front camera (voidce)|Pass| 22 | |12|Memory leak detect|Pass| 23 | |13|Zoom|Pass| 24 | ||Zoom with Capture|Pass| 25 | ||Zoom with Record|Pass| 26 | |14|Focus|Watch| 27 | |15|Video duration|Pass| 28 | 29 | ## 2、Camera1 with SurfaceView 30 | 31 | |No|Item|OnePlus6| 32 | |:-----:|:-----|:-----:| 33 | |1|Open|Pass| 34 | |2|Close|Pass| 35 | |3|Resume|Watch| 36 | |4|Flash|Pass| 37 | ||Flash On|Pass| 38 | ||Flash Off|Pass| 39 | ||Flash Auto|Pass| 40 | |5|Shutter Enable|Pass| 41 | ||Shutter Disable|Pass| 42 | |6|Rotation|Pass| 43 | |7|Change size|Watch| 44 | |8|Capture with rear camera (voidce)|Pass| 45 | |9|Capture with front camera (voidce)|Pass| 46 | |10|Record with rear canera (voidce)|Pass| 47 | |11|Recond with front camera (voidce)|Pass| 48 | |12|Memory leak detect|Pass| 49 | |13|Zoom|Pass| 50 | ||Zoom with Capture|Pass| 51 | ||Zoom with Record|Pass| 52 | |14|Focus|Watch| 53 | |15|Video duration|Pass| 54 | 55 | ## 3、Camera2 with TextureView 56 | 57 | |No|Item|OnePlus6| 58 | |:-----:|:-----|:-----:| 59 | |1|Open|Pass| 60 | |2|Close|Pass| 61 | |3|Resume|Watch| 62 | |4|Flash|Pass| 63 | ||Flash On|Pass| 64 | ||Flash Off|Pass| 65 | ||Flash Auto|Pass| 66 | |5|Shutter Enable|Pass| 67 | ||Shutter Disable|Pass| 68 | |6|Rotation|Pass| 69 | ||Rotation with Capture|Pass| 70 | ||Rotation with Record|Pass| 71 | |7|Change size|Watch| 72 | |8|Capture with rear camera (voidce)|Pass| 73 | |9|Capture with front camera (voidce)|Pass| 74 | |10|Record with rear canera (voidce)|Pass| 75 | |11|Recond with front camera (voidce)|Pass| 76 | |12|Memory leak detect|Pass| 77 | |13|Zoom|Pass| 78 | ||Zoom with Capture|Pass| 79 | ||Zoom with Record|Pass| 80 | |14|Focus|Watch| 81 | |15|Video duration|Pass| 82 | 83 | Tested on Devices: OnePlus6 84 | 85 | ## 4、Camera2 with SurfaceView 86 | 87 | |No|Item|OnePlus6| 88 | |:-----:|:-----|:-----:| 89 | |1|Open|| 90 | |2|Close|| 91 | |3|Resume|| 92 | |4|Flash|| 93 | ||Flash On|| 94 | ||Flash Off|| 95 | ||Flash Auto|| 96 | |5|Shutter Enable|| 97 | ||Shutter Disable|| 98 | |6|Rotation|| 99 | ||Rotation with Capture|| 100 | ||Rotation with Record|| 101 | |7|Change size|| 102 | |8|Capture with rear camera (voidce)|| 103 | |9|Capture with front camera (voidce)|| 104 | |10|Record with rear canera (voidce)|| 105 | |11|Recond with front camera (voidce)|| 106 | |12|Memory leak detect|| 107 | |13|Zoom|| 108 | ||Zoom with Capture|| 109 | ||Zoom with Record|| 110 | |14|Focus|| 111 | |15|Video duration|| 112 | 113 | ## Issues and Status 114 | 115 | ### 0.0.1-beta 116 | 117 | - [x] Crash when get max zoom while the camera was not prepared (the camera parameters was not calculated when trying to get max zoom) 118 | - [x] sometime failed to calculate video size when switch camera face 119 | - [x] sometime preview is distorted when switch camera face for camera2 120 | -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/config/calculator/CameraSizeCalculator.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.config.calculator 2 | 3 | import me.shouheng.icamera.config.size.AspectRatio 4 | import me.shouheng.icamera.config.size.Size 5 | import me.shouheng.icamera.enums.CameraType 6 | import me.shouheng.icamera.enums.MediaQuality 7 | 8 | /** 9 | * Calculator size for camera. You may implement this interface to add your own camera 10 | * size calculation logic. 11 | * 12 | * @see me.shouheng.icamera.config.calculator.impl.CameraSizeCalculatorImpl as an example 13 | * 14 | * 15 | * @author WngShhng (shouheng2015@gmail.com) 16 | * @version 2019/4/13 22:58 17 | */ 18 | interface CameraSizeCalculator { 19 | /** 20 | * Initialize values of calculator. 21 | * 22 | * @param expectAspectRatio expect aspect ratio 23 | * @param expectSize expect size 24 | * @param mediaQuality expect media quality 25 | * @param previewSizes support preview sizes 26 | * @param pictureSizes support picture sizes 27 | * @param videoSizes support video sizes, might be empty of the 28 | * camera don't separate preview and video output 29 | */ 30 | fun init( 31 | expectAspectRatio: AspectRatio, 32 | expectSize: Size?, 33 | @MediaQuality mediaQuality: Int, 34 | previewSizes: List, 35 | pictureSizes: List, 36 | videoSizes: List 37 | ) 38 | 39 | /** 40 | * Change expect aspect ratio. You can implement this method to get the new desired 41 | * aspect ratio and clear the calculated values cache. Anyway this is the method 42 | * we used to notify you the camera state changed. 43 | * 44 | * See also, 45 | * @see .changeExpectSize 46 | * @see .changeMediaQuality 47 | * @param expectAspectRatio the new expect aspect ratio 48 | */ 49 | fun changeExpectAspectRatio(expectAspectRatio: AspectRatio) 50 | 51 | /** 52 | * Change expect size 53 | * 54 | * @param expectSize the new expect size 55 | */ 56 | fun changeExpectSize(expectSize: Size) 57 | 58 | /** 59 | * Change expect media quality 60 | * 61 | * @param mediaQuality the new expect media quality 62 | */ 63 | fun changeMediaQuality(@MediaQuality mediaQuality: Int) 64 | 65 | /** 66 | * Get calculated picture size 67 | * 68 | * @param cameraType camera type, aka, camera1 or camera2 69 | * @return the picture size 70 | */ 71 | fun getPictureSize(@CameraType cameraType: Int): Size? 72 | 73 | /** 74 | * Get calculated picture preview size 75 | * 76 | * @param cameraType camera type, aka, camera1 or camera2 77 | * @return the picture preview size 78 | */ 79 | fun getPicturePreviewSize(@CameraType cameraType: Int): Size? 80 | 81 | /** 82 | * Get calculated video size 83 | * 84 | * @param cameraType camera type, aka, camera1 or camera2 85 | * @return the video size 86 | */ 87 | fun getVideoSize(@CameraType cameraType: Int): Size? 88 | 89 | /** 90 | * Get calculated video preview size 91 | * 92 | * @param cameraType camera type, aka, camera1 or camera2 93 | * @return the video preview size 94 | */ 95 | fun getVideoPreviewSize(@CameraType cameraType: Int): Size? 96 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/config/size/Size.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.config.size 2 | 3 | import android.annotation.TargetApi 4 | import android.hardware.Camera 5 | import android.os.Build 6 | import androidx.annotation.IntRange 7 | import java.util.* 8 | 9 | /** 10 | * The standard size to use in camera. 11 | * 12 | * @author WngShhng (shouheng2015@gmail.com) 13 | * @version 2019/4/13 23:09 14 | */ 15 | class Size private constructor( 16 | /** The width of size. */ 17 | @param:IntRange(from = 1) val width: Int, 18 | /** The height of size. */ 19 | @param:IntRange(from = 0) val height: Int 20 | ) { 21 | 22 | /** The area of size, call [.area] to get size. */ 23 | private var area = -1 24 | 25 | /** 26 | * The height width ratio of size:
ratio = height / width
. 27 | * Call [.ratio] to get ratio. 28 | */ 29 | private var ratio = 0.0 30 | 31 | /** 32 | * The area of current size, calculated only when necessary. 33 | * 34 | * @return the area of size. 35 | */ 36 | fun area(): Int { 37 | if (area == -1) { 38 | area = width * height 39 | } 40 | return area 41 | } 42 | 43 | /** 44 | * The ratio of current size, calculated only when necessary. 45 | * 46 | * @return the ratio 47 | */ 48 | fun ratio(): Double { 49 | if (ratio == 0.0 && width != 0) { 50 | ratio = height.toDouble() / width 51 | } 52 | return ratio 53 | } 54 | 55 | override fun equals(other: Any?): Boolean { 56 | if (this === other) return true 57 | if (other == null || javaClass != other.javaClass) return false 58 | val size = other as Size 59 | return if (width != size.width) false else height == size.height 60 | } 61 | 62 | override fun hashCode(): Int { 63 | var result = width 64 | result = 31 * result + height 65 | return result 66 | } 67 | 68 | override fun toString(): String { 69 | return "($width, $height)" 70 | } 71 | 72 | companion object { 73 | /** 74 | * Get size of given width and height. 75 | * 76 | * @param width the width 77 | * @param height the height 78 | * @return the size 79 | */ 80 | fun of(@IntRange(from = 1) width: Int, @IntRange(from = 0) height: Int): Size = Size(width, height) 81 | 82 | /** 83 | * Get sizes from [Camera.Size] for camera1. 84 | * 85 | * @param cameraSizes the camera sizes support of camera1 86 | * @return the standard size 87 | */ 88 | fun fromList(cameraSizes: List): List { 89 | return cameraSizes.map { of(it.width, it.height) } 90 | } 91 | 92 | /** 93 | * Get sizes from [android.util.Size] for camera2. 94 | * 95 | * @param cameraSizes the camera sizes supported by camera2 96 | * @return the standard size 97 | */ 98 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 99 | fun fromList(cameraSizes: Array): List { 100 | return cameraSizes.map { of(it.width, it.height) } 101 | } 102 | } 103 | 104 | } -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/App.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample 2 | 3 | import android.annotation.SuppressLint 4 | import android.app.Application 5 | import android.util.Log 6 | import com.squareup.leakcanary.LeakCanary 7 | import me.shouheng.icamera.config.ConfigurationProvider 8 | import me.shouheng.icamera.util.LogLevel 9 | import me.shouheng.icamera.util.LogWatcher 10 | import me.shouheng.icamerasample.activity.MainActivity 11 | import me.shouheng.uix.common.bean.TextStyleBean 12 | import me.shouheng.uix.pages.CrashReportActivity 13 | import me.shouheng.utils.app.ResUtils 14 | import me.shouheng.utils.permission.Permission 15 | import me.shouheng.utils.permission.PermissionUtils 16 | import me.shouheng.utils.stability.CrashHelper 17 | import me.shouheng.utils.stability.L 18 | import me.shouheng.utils.store.PathUtils 19 | import me.shouheng.vmlib.VMLib 20 | import java.io.File 21 | 22 | /** 23 | * App 24 | * 25 | * @author WngShhng 26 | * @version 2019-12-28 15:47 27 | */ 28 | class App : Application() { 29 | 30 | override fun onCreate() { 31 | super.onCreate() 32 | application = this 33 | // initialize the vmlib 34 | VMLib.onCreate(this) 35 | // log 36 | L.getConfig().setLogSwitch(BuildConfig.DEBUG) 37 | configCrashHelper(application) 38 | // set iCamera log switch 39 | ConfigurationProvider.get().isDebug = BuildConfig.DEBUG 40 | // leak canary used to detect memory leak of camera 41 | LeakCanary.install(this) 42 | ConfigurationProvider.get().addLogWatcher(object : LogWatcher { 43 | override fun onLog(level: LogLevel, tag: String, msg: String?) { 44 | when(level) { 45 | LogLevel.V -> { Log.v("__I_CAMERA_$tag", msg) } 46 | LogLevel.I -> { Log.i("__I_CAMERA_$tag", msg) } 47 | LogLevel.D -> { Log.d("__I_CAMERA_$tag", msg) } 48 | LogLevel.W -> { Log.w("__I_CAMERA_$tag", msg) } 49 | LogLevel.E -> { Log.e("__I_CAMERA_$tag", msg) } 50 | } 51 | } 52 | }) 53 | } 54 | 55 | companion object { 56 | private lateinit var application: Application 57 | fun app(): Application = application 58 | @SuppressLint("MissingPermission") 59 | fun configCrashHelper(application: Application) { 60 | // crash detect tools, the crash log was saved to : data/data/package_name/files/crash 61 | if (PermissionUtils.hasPermissions(Permission.STORAGE)) { 62 | CrashHelper.init(application, 63 | File(PathUtils.getExternalAppFilesPath(), "crash") 64 | ) { crashInfo, _ -> 65 | CrashReportActivity.Companion.Builder(application) 66 | .setRestartActivity(MainActivity::class.java) 67 | .setMessage(crashInfo) 68 | .setImage(R.drawable.uix_crash_error_image) 69 | .setTitle(ResUtils.getString(R.string.main_common_crash_happened)) 70 | .setButtonStyle(TextStyleBean().apply { 71 | textSize = 18f 72 | }) 73 | .launch() 74 | } 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/filter/JFAVoronoiFilter.java: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.filter; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | 6 | import me.shouheng.icamerasample.R; 7 | import me.shouheng.icamerasample.render.MyGLUtils; 8 | import me.shouheng.icamerasample.render.RenderBuffer; 9 | 10 | public class JFAVoronoiFilter extends CameraFilter { 11 | private int programImg; 12 | private int programA; 13 | private int programB; 14 | private int programC; 15 | 16 | private RenderBuffer bufA; 17 | private RenderBuffer bufB; 18 | private RenderBuffer bufC; 19 | 20 | public JFAVoronoiFilter(Context context) { 21 | super(context); 22 | 23 | // Build shaders 24 | programImg = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.voronoi); 25 | programA = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.voronoi_buf_a); 26 | programB = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.voronoi_buf_b); 27 | programC = MyGLUtils.buildProgram(context, R.raw.vertext, R.raw.voronoi_buf_c); 28 | } 29 | 30 | @Override 31 | public void onDraw(int cameraTexId, int canvasWidth, int canvasHeight) { 32 | // TODO move? 33 | if (bufA == null || bufA.getWidth() != canvasWidth || bufB.getHeight() != canvasHeight) { 34 | // Create new textures for buffering 35 | bufA = new RenderBuffer(canvasWidth, canvasHeight, GLES20.GL_TEXTURE4); 36 | bufB = new RenderBuffer(canvasWidth, canvasHeight, GLES20.GL_TEXTURE5); 37 | bufC = new RenderBuffer(canvasWidth, canvasHeight, GLES20.GL_TEXTURE6); 38 | } 39 | 40 | // Render to buf a 41 | setupShaderInputs(programA, 42 | new int[]{canvasWidth, canvasHeight}, 43 | new int[]{cameraTexId, bufA.getTexId()}, 44 | new int[][]{new int[]{canvasWidth, canvasHeight}, new int[]{canvasWidth, canvasHeight}}); 45 | bufA.bind(); 46 | GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 47 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 48 | bufA.unbind(); 49 | GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 50 | 51 | 52 | // Render to buf b 53 | setupShaderInputs(programB, 54 | new int[]{canvasWidth, canvasHeight}, 55 | new int[]{bufB.getTexId(), bufA.getTexId()}, 56 | new int[][]{new int[]{canvasWidth, canvasHeight}, new int[]{canvasWidth, canvasHeight}}); 57 | bufB.bind(); 58 | GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 59 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 60 | bufB.unbind(); 61 | GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 62 | 63 | 64 | // Render to buf c 65 | setupShaderInputs(programC, 66 | new int[]{canvasWidth, canvasHeight}, 67 | new int[]{bufC.getTexId(), bufB.getTexId()}, 68 | new int[][]{new int[]{canvasWidth, canvasHeight}, new int[]{canvasWidth, canvasHeight}}); 69 | bufC.bind(); 70 | GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 71 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 72 | bufC.unbind(); 73 | GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 74 | 75 | 76 | // Render to screen 77 | setupShaderInputs(programImg, 78 | new int[]{canvasWidth, canvasHeight}, 79 | new int[]{bufC.getTexId(), bufA.getTexId()}, 80 | new int[][]{new int[]{canvasWidth, canvasHeight}, new int[]{canvasWidth, canvasHeight}}); 81 | GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/preview/impl/TexturePreview.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.preview.impl 2 | 3 | import android.content.Context 4 | import android.graphics.SurfaceTexture 5 | import android.view.* 6 | import android.view.TextureView.SurfaceTextureListener 7 | import me.shouheng.icamera.enums.PreviewViewType 8 | 9 | /** 10 | * Camera preview implementation based on [TextureView]. 11 | * 12 | * @author WngShhng (shouheng2015@gmail.com) 13 | * @version 2019/4/13 22:54 14 | */ 15 | class TexturePreview(context: Context, parent: ViewGroup) : BaseCameraPreview() { 16 | 17 | override var surfaceTexture: SurfaceTexture? = null 18 | private set 19 | 20 | private val textureView: TextureView = TextureView(context) 21 | 22 | override val surface: Surface 23 | get() = Surface(surfaceTexture) 24 | 25 | @get:PreviewViewType 26 | override val previewType: Int 27 | get() = PreviewViewType.TEXTURE_VIEW 28 | 29 | override var surfaceHolder: SurfaceHolder? = null 30 | 31 | override val view: View 32 | get() = textureView 33 | 34 | /*-----------------------------------------inner methods---------------------------------------------*/ 35 | private fun updateSurfaceTexture(surfaceTexture: SurfaceTexture, width: Int, height: Int) { 36 | this.surfaceTexture = surfaceTexture 37 | setSize(width, height) 38 | } 39 | 40 | init { 41 | textureView.layoutParams = ViewGroup.LayoutParams( 42 | ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT 43 | ) 44 | parent.addView(textureView) 45 | textureView.surfaceTextureListener = object : SurfaceTextureListener { 46 | /** 47 | * Invoked when a [TextureView]'s SurfaceTexture is ready for use. 48 | * 49 | * @param surface The surface returned by 50 | * [android.view.TextureView.getSurfaceTexture] 51 | * @param width The width of the surface 52 | * @param height The height of the surface 53 | */ 54 | override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) { 55 | updateSurfaceTexture(surface, width, height) 56 | notifyPreviewAvailable() 57 | } 58 | 59 | /** 60 | * Invoked when the [SurfaceTexture]'s buffers size changed. 61 | * 62 | * @param surface The surface returned by 63 | * [android.view.TextureView.getSurfaceTexture] 64 | * @param width The new width of the surface 65 | * @param height The new height of the surface 66 | */ 67 | override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) { 68 | updateSurfaceTexture(surface, width, height) 69 | notifyPreviewAvailable() 70 | } 71 | 72 | /** 73 | * Invoked when the specified [SurfaceTexture] is about to be destroyed. 74 | * If returns true, no rendering should happen inside the surface texture after this method 75 | * is invoked. If returns false, the client needs to call [SurfaceTexture.release]. 76 | * Most applications should return true. 77 | * 78 | * @param surface The surface about to be destroyed 79 | */ 80 | override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean { 81 | updateSurfaceTexture(surface, 0, 0) 82 | return true 83 | } 84 | 85 | override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {/* noop */ } 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/preview/impl/SurfacePreview.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.preview.impl 2 | 3 | import android.content.Context 4 | import android.graphics.SurfaceTexture 5 | import android.view.* 6 | import me.shouheng.icamera.enums.PreviewViewType 7 | 8 | /** 9 | * Camera preview implementation based on [SurfaceView]. 10 | * 11 | * @author WngShhng (shouheng2015@gmail.com) 12 | * @version 2019/4/13 22:53 13 | */ 14 | class SurfacePreview(context: Context, parent: ViewGroup) : BaseCameraPreview() { 15 | 16 | private val surfaceView: SurfaceView = SurfaceView(context) 17 | 18 | override val surface: Surface? 19 | get() = surfaceHolder?.surface 20 | 21 | @get:PreviewViewType 22 | override val previewType: Int 23 | get() = PreviewViewType.SURFACE_VIEW 24 | 25 | override var surfaceHolder: SurfaceHolder? = null 26 | 27 | override val surfaceTexture: SurfaceTexture? get() = null 28 | 29 | override val view: View get() = surfaceView 30 | 31 | /*-----------------------------------------inner methods---------------------------------------------*/ 32 | private fun updateSurfaceTexture(surfaceHolder: SurfaceHolder, width: Int, height: Int) { 33 | this.surfaceHolder = surfaceHolder 34 | setSize(width, height) 35 | } 36 | 37 | init { 38 | surfaceView.layoutParams = ViewGroup.LayoutParams( 39 | ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT 40 | ) 41 | parent.addView(surfaceView) 42 | surfaceHolder = surfaceView.holder 43 | // Enable or disable option to keep the screen turned on while this 44 | // surface is displayed. The default is false, allowing it to turn off. 45 | // This is safe to call from any thread. 46 | surfaceHolder?.setKeepScreenOn(true) 47 | surfaceHolder?.addCallback(object : SurfaceHolder.Callback { 48 | /** 49 | * This is called immediately after the surface is first created. 50 | * Implementations of this should start up whatever rendering code 51 | * they desire. Note that only one thread can ever draw into 52 | * a [Surface], so you should not draw into the Surface here 53 | * if your normal rendering will be in another thread. 54 | * 55 | * @param holder The SurfaceHolder whose surface is being created. 56 | */ 57 | override fun surfaceCreated(holder: SurfaceHolder) { /* noop */ } 58 | 59 | /** 60 | * This is called immediately after any structural changes (format or 61 | * size) have been made to the surface. You should at this point update 62 | * the imagery in the surface. This method is always called at least 63 | * once, after [.surfaceCreated]. 64 | * 65 | * @param holder The SurfaceHolder whose surface has changed. 66 | * @param format The new PixelFormat of the surface. 67 | * @param width The new width of the surface. 68 | * @param height The new height of the surface. 69 | */ 70 | override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) { 71 | updateSurfaceTexture(holder, width, height) 72 | notifyPreviewAvailable() 73 | } 74 | 75 | /** 76 | * This is called immediately before a surface is being destroyed. After 77 | * returning from this call, you should no longer try to access this 78 | * surface. If you have a rendering thread that directly accesses 79 | * the surface, you must ensure that thread is no longer touching the 80 | * Surface before returning from this function. 81 | * 82 | * @param holder The SurfaceHolder whose surface is being destroyed. 83 | */ 84 | override fun surfaceDestroyed(holder: SurfaceHolder) { 85 | updateSurfaceTexture(holder, 0, 0) 86 | } 87 | }) 88 | } 89 | } -------------------------------------------------------------------------------- /icamera/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'kotlin-android' 3 | //apply plugin: 'com.novoda.bintray-release' 4 | apply plugin: 'maven-publish' 5 | apply plugin: 'signing' 6 | 7 | android { 8 | compileSdkVersion rootProject.ext.compileSdkVersion 9 | defaultConfig { 10 | minSdkVersion rootProject.ext.minSdkVersion 11 | targetSdkVersion rootProject.ext.targetSdkVersion 12 | versionCode 1 13 | versionName "1.0" 14 | testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | android { 23 | lintOptions { 24 | abortOnError false 25 | } 26 | } 27 | } 28 | 29 | dependencies { 30 | implementation fileTree(dir: 'libs', include: ['*.jar']) 31 | implementation "androidx.appcompat:appcompat:1.0.0" 32 | compileOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 33 | } 34 | 35 | //publish { 36 | // userOrg = 'easymark' 37 | // groupId = 'me.shouheng.icamera' 38 | // artifactId = 'icamera' 39 | // repoName = 'Android' 40 | // publishVersion = rootProject.ext.publishVersion 41 | // desc = 'The camera library for Android.' 42 | // website = 'https://github.com/Shouheng88/iCamera' 43 | //} 44 | 45 | task androidSourcesJar(type: Jar) { 46 | archiveClassifier.set("sources") 47 | from android.sourceSets.main.java.source 48 | exclude "**/R.class" 49 | exclude "**/BuildConfig.class" 50 | } 51 | 52 | publishing { 53 | // 定义发布什么 54 | publications { 55 | mavenJava(MavenPublication) { 56 | groupId 'com.github.Shouheng88' 57 | artifactId 'icamera' 58 | version rootProject.ext.publishVersion 59 | // Two artifacts, the `aar` and the sources 60 | artifact("$buildDir/outputs/aar/${project.getName()}-release.aar") 61 | artifact androidSourcesJar 62 | pom { 63 | // 构件名称,区别于 artifactId,可以理解为 artifactName 64 | name = 'Utils-core' 65 | // 构件描述 66 | description = 'Android Camera Library' 67 | // 构件主页 68 | url = 'https://github.com/Shouheng88/iCamera' 69 | // 许可证名称和地址 70 | licenses { 71 | license { 72 | name = 'The Apache License, Version 2.0' 73 | url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' 74 | } 75 | } 76 | // 开发者信息 77 | developers { 78 | developer { 79 | name = 'ShouHeng' 80 | email = 'shouheng2015@gmail.com' 81 | } 82 | } 83 | // 版本控制仓库地址 84 | scm { 85 | url = 'https://github.com/Shouheng88/iCamera' 86 | connection = 'scm:git:github.com/Shouheng88/iCamera.git' 87 | developerConnection = 'scm:git:ssh://git@github.com/Shouheng88/iCamera.git' 88 | } 89 | } 90 | } 91 | } 92 | // 定义发布到哪里 93 | repositories { 94 | maven { 95 | def releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/" 96 | def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/" 97 | // You only need this if you want to publish snapshots, otherwise just set the URL 98 | // to the release repo directly 99 | url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl 100 | credentials { 101 | // 这里就是之前在 issues.sonatype.org 注册的账号 102 | username ossrhUsername 103 | password ossrhPassword 104 | } 105 | } 106 | } 107 | } 108 | 109 | signing { 110 | sign publishing.publications 111 | } 112 | -------------------------------------------------------------------------------- /sample/.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | xmlns:android 17 | 18 | ^$ 19 | 20 | 21 | 22 |
23 |
24 | 25 | 26 | 27 | xmlns:.* 28 | 29 | ^$ 30 | 31 | 32 | BY_NAME 33 | 34 |
35 |
36 | 37 | 38 | 39 | .*:id 40 | 41 | http://schemas.android.com/apk/res/android 42 | 43 | 44 | 45 |
46 |
47 | 48 | 49 | 50 | .*:name 51 | 52 | http://schemas.android.com/apk/res/android 53 | 54 | 55 | 56 |
57 |
58 | 59 | 60 | 61 | name 62 | 63 | ^$ 64 | 65 | 66 | 67 |
68 |
69 | 70 | 71 | 72 | style 73 | 74 | ^$ 75 | 76 | 77 | 78 |
79 |
80 | 81 | 82 | 83 | .* 84 | 85 | ^$ 86 | 87 | 88 | BY_NAME 89 | 90 |
91 |
92 | 93 | 94 | 95 | .* 96 | 97 | http://schemas.android.com/apk/res/android 98 | 99 | 100 | ANDROID_ATTRIBUTE_ORDER 101 | 102 |
103 |
104 | 105 | 106 | 107 | .* 108 | 109 | .* 110 | 111 | 112 | BY_NAME 113 | 114 |
115 |
116 |
117 |
118 | 119 | 121 |
122 |
-------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/util/ImageHelper.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.util 2 | 3 | import android.graphics.* 4 | import android.media.Image 5 | import android.os.Build 6 | import androidx.annotation.RequiresApi 7 | import java.io.ByteArrayOutputStream 8 | import java.io.IOException 9 | import java.nio.ReadOnlyBufferException 10 | import kotlin.experimental.and 11 | import kotlin.experimental.inv 12 | 13 | object ImageHelper { 14 | 15 | @RequiresApi(api = Build.VERSION_CODES.KITKAT) 16 | fun convertYUV_420_888toNV21(image: Image): ByteArray { 17 | val width = image.width 18 | val height = image.height 19 | val ySize = width * height 20 | val uvSize = width * height / 4 21 | val nv21 = ByteArray(ySize + uvSize * 2) 22 | val yBuffer = image.planes[0].buffer // Y 23 | val uBuffer = image.planes[1].buffer // U 24 | val vBuffer = image.planes[2].buffer // V 25 | var rowStride = image.planes[0].rowStride 26 | var pos = 0 27 | if (rowStride == width) { // likely 28 | yBuffer[nv21, 0, ySize] 29 | pos += ySize 30 | } else { 31 | var yBufferPos = -rowStride // not an actual position 32 | while (pos < ySize) { 33 | yBufferPos += rowStride 34 | yBuffer.position(yBufferPos) 35 | yBuffer[nv21, pos, width] 36 | pos += width 37 | } 38 | } 39 | rowStride = image.planes[2].rowStride 40 | val pixelStride = image.planes[2].pixelStride 41 | if (pixelStride == 2 && rowStride == width && uBuffer[0] == vBuffer[1]) { 42 | // maybe V an U planes overlap as per NV21, which means vBuffer[1] is alias of uBuffer[0] 43 | val savePixel = vBuffer[1] 44 | try { 45 | vBuffer.put(1, savePixel.inv()) 46 | if (uBuffer[0] == savePixel.inv()) { 47 | vBuffer.put(1, savePixel) 48 | vBuffer[nv21, ySize, uvSize] 49 | return nv21 // shortcut 50 | } 51 | } catch (ex: ReadOnlyBufferException) { 52 | XLog.e("ImageHelper", "ReadOnlyBufferException :$ex") 53 | } 54 | vBuffer.put(1, savePixel) 55 | } 56 | var row = 0 57 | val row_len = height / 2 58 | while (row < row_len) { 59 | var col = 0 60 | val col_len = width / 2 61 | while (col < col_len) { 62 | val vuPos = col * pixelStride + row * rowStride 63 | nv21[pos++] = vBuffer[vuPos] 64 | nv21[pos++] = uBuffer[vuPos] 65 | col++ 66 | } 67 | row++ 68 | } 69 | return nv21 70 | } 71 | 72 | fun convertYUV420_NV21toARGB8888(data: ByteArray, width: Int, height: Int): Int { 73 | val size = width * height 74 | val bri = IntArray(4) 75 | var u: Int 76 | var v: Int 77 | val y1: Int 78 | val y2: Int 79 | val y3: Int 80 | val y4: Int 81 | 82 | // i along Y and the final pixels 83 | // k along pixels U and V 84 | var i = 0 85 | y1 = (data[i] and 0xff.toByte()).toInt() 86 | y2 = (data[i + 1] and 0xff.toByte()).toInt() 87 | y3 = (data[width + i] and 0xff.toByte()).toInt() 88 | y4 = (data[width + i + 1] and 0xff.toByte()).toInt() 89 | bri[0] = y1 90 | bri[1] = y2 91 | bri[2] = y3 92 | bri[3] = y4 93 | var max = 0 94 | val j = 0 95 | while (i < bri.size) { 96 | if (bri[j] > max) { 97 | max = bri[j] 98 | } 99 | i++ 100 | } 101 | return max 102 | } 103 | 104 | fun convertNV21ToBitmap(nv21: ByteArray?, width: Int, height: Int): Bitmap? { 105 | var bitmap: Bitmap? = null 106 | try { 107 | val image = YuvImage(nv21, ImageFormat.NV21, width, height, null) 108 | val stream = ByteArrayOutputStream() 109 | image.compressToJpeg(Rect(0, 0, width, height), 80, stream) 110 | bitmap = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size()) 111 | stream.close() 112 | } catch (e: IOException) { 113 | XLog.e("ImageHelper", "nv21ToBitmap : $e") 114 | } 115 | return bitmap 116 | } 117 | } -------------------------------------------------------------------------------- /sample/app/src/main/java/me/shouheng/icamerasample/activity/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamerasample.activity 2 | 3 | import android.os.Build 4 | import android.os.Bundle 5 | import androidx.annotation.RequiresApi 6 | import me.shouheng.icamera.config.ConfigurationProvider 7 | import me.shouheng.icamera.config.creator.impl.* 8 | import me.shouheng.icamera.util.CameraHelper 9 | import me.shouheng.icamerasample.R 10 | import me.shouheng.icamerasample.databinding.ActivityMainBinding 11 | import me.shouheng.utils.ktx.checkPermissions 12 | import me.shouheng.utils.ktx.onDebouncedClick 13 | import me.shouheng.utils.ktx.start 14 | import me.shouheng.utils.permission.Permission 15 | import me.shouheng.utils.stability.L 16 | import me.shouheng.utils.store.SPUtils 17 | import me.shouheng.utils.ui.BarUtils 18 | import me.shouheng.vmlib.base.CommonActivity 19 | import me.shouheng.vmlib.comn.EmptyViewModel 20 | 21 | /** 22 | * Main activity 23 | * 24 | * @author WngShhng (shouheng2015@gmail.com) 25 | * @version 2019/4/13 22:42 26 | */ 27 | class MainActivity : CommonActivity() { 28 | 29 | override fun getLayoutResId(): Int = R.layout.activity_main 30 | 31 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP) 32 | override fun doCreateView(savedInstanceState: Bundle?) { 33 | L.d("MainActivity", "doCreateView") 34 | BarUtils.setStatusBarLightMode(window, false) 35 | ConfigurationProvider.get().isDebug = true 36 | setSupportActionBar(binding.toolbar) 37 | 38 | binding.rbCamera1.setOnCheckedChangeListener { _, isChecked -> if (isChecked) { switchToCameraOption(0) } } 39 | binding.rbCamera2.setOnCheckedChangeListener { _, isChecked -> if (isChecked) { switchToCameraOption(1) } } 40 | binding.rbCamera.setOnCheckedChangeListener { _, isChecked -> if (isChecked) { switchToCameraOption(2) } } 41 | 42 | binding.rbSurface.setOnCheckedChangeListener { _, isChecked -> if (isChecked) { switchToPreviewOption(0) } } 43 | binding.rbTexture.setOnCheckedChangeListener { _, isChecked -> if (isChecked) { switchToPreviewOption(1) } } 44 | binding.rbPlatform.setOnCheckedChangeListener { _, isChecked -> if (isChecked) { switchToPreviewOption(2) } } 45 | 46 | switchToCameraOption(SPUtils.get().getInt("__camera_option", 2)) 47 | switchToPreviewOption(SPUtils.get().getInt("__preview_option", 2)) 48 | 49 | // pre-prepare camera2 params, this option will save few milliseconds while launch camera2 50 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 51 | ConfigurationProvider.get().prepareCamera2(this) 52 | } 53 | 54 | binding.btnOpen.onDebouncedClick { openCamera() } 55 | } 56 | 57 | private fun openCamera() { 58 | checkPermissions({ 59 | val cameras = CameraHelper.getCameras(context) 60 | when { 61 | cameras.isEmpty() -> { 62 | toast("No camera on this device") 63 | } 64 | cameras.size == 1 -> { 65 | val face = cameras[0] 66 | ConfigurationProvider.get().defaultCameraFace = face 67 | start(CameraActivity::class.java) 68 | toast("Device only has one camera [$face]") 69 | } 70 | else -> { 71 | start(CameraActivity::class.java) 72 | } 73 | } 74 | }, Permission.CAMERA, Permission.STORAGE, Permission.MICROPHONE) 75 | } 76 | 77 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP) 78 | private fun switchToCameraOption(option: Int) { 79 | ConfigurationProvider.get().cameraManagerCreator = when(option) { 80 | 0 -> Camera1OnlyCreator() 81 | 1 -> Camera2OnlyCreator() 82 | else -> CameraManagerCreatorImpl() 83 | } 84 | when(option) { 85 | 0 -> binding.rbCamera1 86 | 1 -> binding.rbCamera2 87 | else -> binding.rbCamera 88 | }.isChecked = true 89 | SPUtils.get().put("__camera_option", option) 90 | } 91 | 92 | private fun switchToPreviewOption(option: Int) { 93 | ConfigurationProvider.get().cameraPreviewCreator = when(option) { 94 | 0 -> SurfaceViewOnlyCreator() 95 | 1 -> TextureViewOnlyCreator() 96 | else -> CameraPreviewCreatorImpl() 97 | } 98 | when(option) { 99 | 0 -> binding.rbSurface 100 | 1 -> binding.rbTexture 101 | else -> binding.rbPlatform 102 | }.isChecked = true 103 | SPUtils.get().put("__preview_option", option) 104 | } 105 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/raw/crosshatch.fsh: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform vec3 iResolution; 4 | uniform float iGlobalTime; 5 | uniform sampler2D iChannel0; 6 | varying vec2 texCoord; 7 | 8 | // The brightnesses at which different hatch lines appear 9 | float hatch_1 = 0.8; 10 | float hatch_2 = 0.6; 11 | float hatch_3 = 0.3; 12 | float hatch_4 = 0.15; 13 | 14 | // How close together hatch lines should be placed 15 | float density = 10.0; 16 | 17 | // How wide hatch lines are drawn. 18 | float width = 1.0; 19 | 20 | // enable GREY_HATCHES for greyscale hatch lines 21 | #define GREY_HATCHES 22 | 23 | // enable COLOUR_HATCHES for coloured hatch lines 24 | #define COLOUR_HATCHES 25 | 26 | #ifdef GREY_HATCHES 27 | float hatch_1_brightness = 0.8; 28 | float hatch_2_brightness = 0.6; 29 | float hatch_3_brightness = 0.3; 30 | float hatch_4_brightness = 0.0; 31 | #else 32 | float hatch_1_brightness = 0.0; 33 | float hatch_2_brightness = 0.0; 34 | float hatch_3_brightness = 0.0; 35 | float hatch_4_brightness = 0.0; 36 | #endif 37 | 38 | float d = 1.0; // kernel offset 39 | 40 | float lookup(vec2 p, float dx, float dy) 41 | { 42 | vec2 uv = (p.xy + vec2(dx * d, dy * d)) / iResolution.xy; 43 | vec4 c = texture2D(iChannel0, uv.xy); 44 | 45 | // return as luma 46 | return 0.2126*c.r + 0.7152*c.g + 0.0722*c.b; 47 | } 48 | 49 | 50 | void mainImage( out vec4 fragColor, in vec2 fragCoord ) 51 | { 52 | // 53 | // Inspired by the technique illustrated at 54 | // http://www.geeks3d.com/20110219/shader-library-crosshatching-glsl-filter/ 55 | // 56 | float ratio = iResolution.y / iResolution.x; 57 | float coordX = fragCoord.x / iResolution.x; 58 | float coordY = fragCoord.y / iResolution.x; 59 | vec2 dstCoord = vec2(coordX, coordY); 60 | vec2 srcCoord = vec2(coordX, coordY / ratio); 61 | vec2 uv = srcCoord.xy; 62 | 63 | vec3 res = vec3(1.0, 1.0, 1.0); 64 | vec4 tex = texture2D(iChannel0, uv); 65 | float brightness = (0.2126*tex.x) + (0.7152*tex.y) + (0.0722*tex.z); 66 | #ifdef COLOUR_HATCHES 67 | // check whether we have enough of a hue to warrant coloring our 68 | // hatch strokes. If not, just use greyscale for our hatch color. 69 | float dimmestChannel = min( min( tex.r, tex.g ), tex.b ); 70 | float brightestChannel = max( max( tex.r, tex.g ), tex.b ); 71 | float delta = brightestChannel - dimmestChannel; 72 | if ( delta > 0.1 ) 73 | tex = tex * ( 1.0 / brightestChannel ); 74 | else 75 | tex.rgb = vec3(1.0,1.0,1.0); 76 | #endif // COLOUR_HATCHES 77 | 78 | if (brightness < hatch_1) 79 | { 80 | if (mod(fragCoord.x + fragCoord.y, density) <= width) 81 | { 82 | #ifdef COLOUR_HATCHES 83 | res = vec3(tex.rgb * hatch_1_brightness); 84 | #else 85 | res = vec3(hatch_1_brightness); 86 | #endif 87 | } 88 | } 89 | 90 | if (brightness < hatch_2) 91 | { 92 | if (mod(fragCoord.x - fragCoord.y, density) <= width) 93 | { 94 | #ifdef COLOUR_HATCHES 95 | res = vec3(tex.rgb * hatch_2_brightness); 96 | #else 97 | res = vec3(hatch_2_brightness); 98 | #endif 99 | } 100 | } 101 | 102 | if (brightness < hatch_3) 103 | { 104 | if (mod(fragCoord.x + fragCoord.y - (density*0.5), density) <= width) 105 | { 106 | #ifdef COLOUR_HATCHES 107 | res = vec3(tex.rgb * hatch_3_brightness); 108 | #else 109 | res = vec3(hatch_3_brightness); 110 | #endif 111 | } 112 | } 113 | 114 | if (brightness < hatch_4) 115 | { 116 | if (mod(fragCoord.x - fragCoord.y - (density*0.5), density) <= width) 117 | { 118 | #ifdef COLOUR_HATCHES 119 | res = vec3(tex.rgb * hatch_4_brightness); 120 | #else 121 | res = vec3(hatch_4_brightness); 122 | #endif 123 | } 124 | } 125 | 126 | vec2 p = fragCoord.xy; 127 | 128 | // simple sobel edge detection, 129 | // borrowed and tweaked from jmk's "edge glow" filter, here: 130 | // https://www.shadertoy.com/view/Mdf3zr 131 | float gx = 0.0; 132 | gx += -1.0 * lookup(p, -1.0, -1.0); 133 | gx += -2.0 * lookup(p, -1.0, 0.0); 134 | gx += -1.0 * lookup(p, -1.0, 1.0); 135 | gx += 1.0 * lookup(p, 1.0, -1.0); 136 | gx += 2.0 * lookup(p, 1.0, 0.0); 137 | gx += 1.0 * lookup(p, 1.0, 1.0); 138 | 139 | float gy = 0.0; 140 | gy += -1.0 * lookup(p, -1.0, -1.0); 141 | gy += -2.0 * lookup(p, 0.0, -1.0); 142 | gy += -1.0 * lookup(p, 1.0, -1.0); 143 | gy += 1.0 * lookup(p, -1.0, 1.0); 144 | gy += 2.0 * lookup(p, 0.0, 1.0); 145 | gy += 1.0 * lookup(p, 1.0, 1.0); 146 | 147 | // hack: use g^2 to conceal noise in the video 148 | float g = gx*gx + gy*gy; 149 | res *= (1.0-g); 150 | 151 | fragColor = vec4(res, 1.0); 152 | } 153 | 154 | void main() { 155 | mainImage(gl_FragColor, texCoord * iResolution.xy); 156 | } -------------------------------------------------------------------------------- /sample/app/src/main/res/menu/filter.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | 39 | 40 | 44 | 45 | 49 | 50 | 54 | 55 | 59 | 60 | 64 | 65 | 69 | 70 | 74 | 75 | 79 | 80 | 84 | 85 | 89 | 90 | 94 | 95 | 99 | 100 | 104 | 105 | 109 | 110 | 114 | 115 | 119 | 120 | 124 | 125 | 129 | 130 | 134 | 135 | 139 | 140 | 144 | 145 | 149 | 150 | 154 | 155 | 159 | 160 | 164 | 165 | 169 | 170 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /icamera/src/main/java/me/shouheng/icamera/config/calculator/impl/CameraSizeCalculatorImpl.kt: -------------------------------------------------------------------------------- 1 | package me.shouheng.icamera.config.calculator.impl 2 | 3 | import android.util.SparseArray 4 | import me.shouheng.icamera.config.ConfigurationProvider 5 | import me.shouheng.icamera.config.calculator.CameraSizeCalculator 6 | import me.shouheng.icamera.config.size.AspectRatio 7 | import me.shouheng.icamera.config.size.Size 8 | import me.shouheng.icamera.enums.MediaQuality 9 | import me.shouheng.icamera.util.CameraHelper 10 | import me.shouheng.icamera.util.CameraHelper.getSizeWithClosestRatio 11 | import me.shouheng.icamera.util.CameraHelper.getSizeWithClosestRatioSizeAndQuality 12 | import me.shouheng.icamera.util.XLog.d 13 | 14 | /** 15 | * Default implementation for [CameraSizeCalculator]. 16 | * 17 | * Sample calculation strategies: 18 | * @see CameraHelper.getSizeWithClosestRatio 19 | * @see CameraHelper.getSizeWithClosestRatioSizeAndQuality 20 | * @author WngShhng (shouheng2015@gmail.com) 21 | * @version 2019/4/13 22:58 22 | */ 23 | class CameraSizeCalculatorImpl : CameraSizeCalculator { 24 | private var previewSizes: List = emptyList() 25 | private var pictureSizes: List = emptyList() 26 | private var videoSizes: List = emptyList() 27 | private var expectAspectRatio: AspectRatio? = null 28 | private var expectSize: Size? = null 29 | 30 | @MediaQuality 31 | private var mediaQuality = 0 32 | private val outPictureSizes = SparseArray() 33 | private val outVideoSizes = SparseArray() 34 | private val outPicturePreviewSizes = SparseArray() 35 | private val outVideoPreviewSizes = SparseArray() 36 | 37 | override fun init( 38 | expectAspectRatio: AspectRatio, 39 | expectSize: Size?, 40 | @MediaQuality mediaQuality: Int, 41 | previewSizes: List, 42 | pictureSizes: List, 43 | videoSizes: List 44 | ) { 45 | this.expectAspectRatio = expectAspectRatio 46 | this.expectSize = expectSize 47 | this.mediaQuality = mediaQuality 48 | this.previewSizes = previewSizes 49 | this.pictureSizes = pictureSizes 50 | this.videoSizes = videoSizes 51 | } 52 | 53 | override fun changeExpectAspectRatio(expectAspectRatio: AspectRatio) { 54 | d("CameraSizeCalculator", "changeExpectAspectRatio : cache cleared") 55 | this.expectAspectRatio = expectAspectRatio 56 | outPictureSizes.clear() 57 | outPicturePreviewSizes.clear() 58 | outVideoSizes.clear() 59 | outVideoPreviewSizes.clear() 60 | } 61 | 62 | override fun changeExpectSize(expectSize: Size) { 63 | d("CameraSizeCalculator", "changeExpectSize : cache cleared") 64 | this.expectSize = expectSize 65 | outPictureSizes.clear() 66 | outPicturePreviewSizes.clear() 67 | outVideoSizes.clear() 68 | outVideoPreviewSizes.clear() 69 | } 70 | 71 | override fun changeMediaQuality(mediaQuality: Int) { 72 | d("CameraSizeCalculator", "changeMediaQuality : cache cleared") 73 | this.mediaQuality = mediaQuality 74 | outPictureSizes.clear() 75 | outPicturePreviewSizes.clear() 76 | outVideoSizes.clear() 77 | outVideoPreviewSizes.clear() 78 | } 79 | 80 | override fun getPictureSize(cameraType: Int): Size? { 81 | var size = outPictureSizes[cameraType] 82 | if (size != null) return size 83 | size = getSizeWithClosestRatioSizeAndQuality( 84 | pictureSizes, expectAspectRatio, expectSize, mediaQuality) 85 | outPictureSizes.put(cameraType, size) 86 | d("CameraSizeCalculator", "getPictureSize : $size") 87 | return size 88 | } 89 | 90 | override fun getPicturePreviewSize(cameraType: Int): Size? { 91 | var size = outPicturePreviewSizes[cameraType] 92 | if (size != null) return size 93 | size = getSizeWithClosestRatio(previewSizes, getPictureSize(cameraType)) 94 | outPicturePreviewSizes.put(cameraType, size) 95 | d("CameraSizeCalculator", "getPicturePreviewSize : $size") 96 | return size 97 | } 98 | 99 | override fun getVideoSize(cameraType: Int): Size? { 100 | var size = outVideoSizes[cameraType] 101 | if (size != null) return size 102 | // fix 2020-05-01 the video size might be empty if the camera don't separate video size and preview size 103 | val sizes = if (videoSizes.isNotEmpty()) videoSizes else previewSizes 104 | size = getSizeWithClosestRatioSizeAndQuality(sizes, expectAspectRatio, expectSize, mediaQuality) 105 | outVideoSizes.put(cameraType, size) 106 | d("CameraSizeCalculator", "getVideoSize : $size") 107 | // fix 2020-05-01, should return the camera video size 108 | return size 109 | } 110 | 111 | override fun getVideoPreviewSize(cameraType: Int): Size? { 112 | var size = outVideoPreviewSizes[cameraType] 113 | if (size != null) return size 114 | size = getSizeWithClosestRatio(previewSizes, getVideoSize(cameraType)) 115 | outVideoPreviewSizes.put(cameraType, size) 116 | d("CameraSizeCalculator", "getVideoPreviewSize : $size") 117 | return size 118 | } 119 | } 120 | --------------------------------------------------------------------------------