├── 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 |
4 |
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 |
8 |
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 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
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 |
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 |
32 |
33 |
34 |
35 |
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 |
15 |
16 |
17 |
18 |
19 |
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 |
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 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
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 |
5 |
6 |
7 |
8 |
9 |
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 |
120 |
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 |
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 |
--------------------------------------------------------------------------------