├── .gitignore ├── .idea ├── caches │ └── build_file_checksums.ser ├── codeStyles │ └── Project.xml ├── gradle.xml ├── inspectionProfiles │ └── Project_Default.xml ├── jarRepositories.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── camera │ │ └── cn │ │ └── cameramaster │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── web │ │ │ ├── css │ │ │ └── login.css │ │ │ ├── image │ │ │ └── logo.png │ │ │ ├── index.html │ │ │ └── login.html │ ├── java │ │ └── camera │ │ │ └── cn │ │ │ └── cameramaster │ │ │ ├── OpenReceiver.java │ │ │ ├── adapter │ │ │ ├── EffectAdapter.java │ │ │ ├── MenuAdapter.java │ │ │ └── SenseAdapter.java │ │ │ ├── base │ │ │ ├── App.java │ │ │ └── BaseActivity.java │ │ │ ├── bean │ │ │ └── Lab.java │ │ │ ├── filter │ │ │ ├── AFilter.java │ │ │ └── TextureFilter.java │ │ │ ├── server │ │ │ ├── AnyEventType.java │ │ │ ├── CoreService.java │ │ │ ├── ServerManager.java │ │ │ ├── TestController.java │ │ │ ├── component │ │ │ │ └── LoggerInterceptor.java │ │ │ ├── model │ │ │ │ └── UserInfo.java │ │ │ └── util │ │ │ │ ├── FileUtils.java │ │ │ │ └── NetUtils.java │ │ │ ├── ui │ │ │ ├── Camera2Activity.java │ │ │ ├── CameraActivity.java │ │ │ ├── CameraSurfaceViewActivity.java │ │ │ ├── CameraVideoActivity.java │ │ │ ├── GoogleCameraActivity.java │ │ │ ├── MainActivity.java │ │ │ └── ShowPicActivity.java │ │ │ ├── util │ │ │ ├── AppConstant.java │ │ │ ├── BitmapUtils.java │ │ │ ├── Camera2Util.java │ │ │ ├── CameraUtil.java │ │ │ ├── CameraV2.java │ │ │ ├── CompareSizesByArea.java │ │ │ ├── FilterEngine.java │ │ │ ├── LabUtil.java │ │ │ ├── MatrixUtils.java │ │ │ ├── Utils.java │ │ │ ├── cameravideo │ │ │ │ ├── CameraHelper.java │ │ │ │ ├── CoordinateTransformer.java │ │ │ │ ├── ICamera2.java │ │ │ │ ├── IVideoControl.java │ │ │ │ └── VideoPlayer.java │ │ │ └── render │ │ │ │ └── CameraV2Renderer.java │ │ │ └── view │ │ │ ├── AnimationTextView.java │ │ │ ├── AutoFitTextureView.java │ │ │ ├── AutoLocateHorizontalView.java │ │ │ ├── AutoTextureView.java │ │ │ ├── AwbSeekBar.java │ │ │ ├── AwbSeekBarChangeListener.java │ │ │ ├── CameraV2GLSurfaceView.java │ │ │ ├── ShowSurfaceView.java │ │ │ └── SleepThread.java │ └── res │ │ ├── anim │ │ ├── alpha_in.xml │ │ └── alpha_out.xml │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── ic_camera.xml │ │ ├── ic_fouces.xml │ │ ├── ic_launcher_background.xml │ │ └── ic_launcher_camera.xml │ │ ├── layout │ │ ├── activity_camera.xml │ │ ├── activity_camera2.xml │ │ ├── activity_camera_sv.xml │ │ ├── activity_camera_video.xml │ │ ├── activity_google_camera.xml │ │ ├── activity_look_camera.xml │ │ ├── activity_main.xml │ │ ├── activity_show_pic.xml │ │ ├── item_age.xml │ │ └── item_rv_text.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── btn_ae.png │ │ ├── btn_album.png │ │ ├── btn_awb.png │ │ ├── btn_camera_turn_n.png │ │ ├── btn_change_camera_normal.png │ │ ├── btn_effect.png │ │ ├── btn_flash_auto_normal.png │ │ ├── btn_flash_off_normal.png │ │ ├── btn_flash_on_normal.png │ │ ├── btn_iso.png │ │ ├── btn_sense.png │ │ ├── btn_zoom.png │ │ ├── flash_auto.png │ │ ├── flash_close.png │ │ ├── flash_open.png │ │ ├── ic_add.png │ │ ├── ic_camera_wb_auto.png │ │ ├── ic_camera_wb_cloudy_daylight.png │ │ ├── ic_camera_wb_daylight.png │ │ ├── ic_camera_wb_fluorescent.png │ │ ├── ic_camera_wb_incandescent.png │ │ ├── ic_camera_wb_shade.png │ │ ├── ic_camera_wb_twilight.png │ │ ├── ic_camera_wb_warm_fluorescent.png │ │ ├── ic_close.png │ │ ├── ic_delete.png │ │ ├── ic_launcher.png │ │ ├── ic_launcher_background.xml │ │ ├── ic_launcher_round.png │ │ ├── ic_minus.png │ │ ├── ic_pause.png │ │ ├── ic_play.png │ │ ├── ic_recording.png │ │ ├── ic_save.png │ │ ├── ic_switch_camera.png │ │ ├── ic_video_close.png │ │ ├── icon_back.xml │ │ ├── icon_camera_a.png │ │ ├── icon_camera_off.png │ │ └── icon_camera_on.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── raw │ │ ├── base_fragment_shader.glsl │ │ └── base_vertex_shader.glsl │ │ ├── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ └── file_paths.xml │ └── test │ └── java │ └── camera │ └── cn │ └── cameramaster │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/caches/build_file_checksums.ser: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangmingchuan/CameraMaster/5340823cd85fea2c819b096efaeb7baa27707c46/.idea/caches/build_file_checksums.ser -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | xmlns:android 14 | 15 | ^$ 16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 | xmlns:.* 25 | 26 | ^$ 27 | 28 | 29 | BY_NAME 30 | 31 |
32 |
33 | 34 | 35 | 36 | .*:id 37 | 38 | http://schemas.android.com/apk/res/android 39 | 40 | 41 | 42 |
43 |
44 | 45 | 46 | 47 | .*:name 48 | 49 | http://schemas.android.com/apk/res/android 50 | 51 | 52 | 53 |
54 |
55 | 56 | 57 | 58 | name 59 | 60 | ^$ 61 | 62 | 63 | 64 |
65 |
66 | 67 | 68 | 69 | style 70 | 71 | ^$ 72 | 73 | 74 | 75 |
76 |
77 | 78 | 79 | 80 | .* 81 | 82 | ^$ 83 | 84 | 85 | BY_NAME 86 | 87 |
88 |
89 | 90 | 91 | 92 | .* 93 | 94 | http://schemas.android.com/apk/res/android 95 | 96 | 97 | ANDROID_ATTRIBUTE_ORDER 98 | 99 |
100 |
101 | 102 | 103 | 104 | .* 105 | 106 | .* 107 | 108 | 109 | BY_NAME 110 | 111 |
112 |
113 |
114 |
115 |
116 |
-------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 36 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | 39 | 40 | 44 | 45 | 49 | 50 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 28 | 45 | 46 | 47 | 48 | 49 | 50 | 52 | 53 | 54 | 55 | 56 | 1.8 57 | 58 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SunCamera 2 | 3 | 一个 学习自定义的 Camera1 、Camera2 、Camera X 和 OpenglES 的Demo 4 | 5 | # 版本迭代 6 | 7 | - 1.3 完善部分bug (暂时停止维护,抽空整理成底层SDK,相对架构来一次深度的学习) 8 | - 1.2 添加 拍照录像及硬件设备信息调节界面 9 | - 1.1 添加 Camera 2 相机使用界面 10 | - 1.0 添加 Camera 1 相机使用界面 11 | 12 | # 感谢 13 | 14 | https://github.com/chensowf/Camera 录像代码部分参考和学习。感谢开源 15 | 16 | 17 | # 效果图 18 | 19 | 1. 目前 拍照 摄像界面 效果界面主要 在 CameraVideoActivity 界面中。 20 | 21 | ![image](https://github.com/yangmingchuan/CameraMaster/blob/5d92dda84ff32038e7abe94a7a15c40eea7f1a66/app/src/main/res/drawable-v24/64F105A2D530CDE27A0F21CBC6C0B877.gif) 22 | 23 | 2.camera+surfaceview 博客地址:https://www.jianshu.com/p/af39024896ce 24 | 25 | ![image](https://upload-images.jianshu.io/upload_images/6188347-cd61d9a329522b0a?imageMogr2/auto-orient/) 26 | 27 | 28 | 3. camera2 + TextureView 博客地址 : https://www.jianshu.com/p/c99fd9dfd77f 29 | 30 | 4. camera2 + glSurfaceview + opengles 博客地址 : https://www.jianshu.com/p/e4ece3f21ec8 31 | 32 | ![image](https://img-blog.csdnimg.cn/2019040210145280.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI3OTQ4NjU5,size_16,color_FFFFFF,t_70) 33 | 34 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 27 5 | defaultConfig { 6 | applicationId "camera.cn.cameramaster" 7 | minSdkVersion 17 8 | targetSdkVersion 27 9 | versionCode 103 10 | versionName "1.0.3" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | debug { 15 | debuggable true 16 | zipAlignEnabled false 17 | minifyEnabled false 18 | shrinkResources false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | 22 | release { 23 | debuggable false 24 | zipAlignEnabled true 25 | minifyEnabled true 26 | shrinkResources true 27 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 28 | } 29 | } 30 | buildToolsVersion '27.0.3' 31 | } 32 | 33 | dependencies { 34 | implementation fileTree(include: ['*.jar'], dir: 'libs') 35 | implementation 'com.android.support:appcompat-v7:27.1.1' 36 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 37 | testImplementation 'junit:junit:4.12' 38 | implementation 'com.android.support:cardview-v7:27.1.1' 39 | implementation 'com.android.support:recyclerview-v7:27.1.1' 40 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 41 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 42 | // butterknife 43 | implementation 'com.jakewharton:butterknife:8.8.1' 44 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1' 45 | // permission 46 | implementation 'com.yanzhenjie:permission:2.0.0-rc4' 47 | implementation 'com.android.support:exifinterface:27.1.1' 48 | // api 49 | implementation 'com.yanzhenjie.andserver:api:2.0.4' 50 | annotationProcessor 'com.yanzhenjie.andserver:processor:2.0.4' 51 | // load json 52 | implementation 'com.alibaba:fastjson:1.2.48' 53 | implementation 'com.yanzhenjie:loading:1.0.0' 54 | // event bus 55 | implementation 'org.greenrobot:eventbus:3.1.1' 56 | 57 | api "io.reactivex.rxjava2:rxjava:2.1.0" 58 | api "io.reactivex.rxjava2:rxandroid:2.1.0" 59 | } 60 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/camera/cn/cameramaster/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("camera.cn.cameramaster", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 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 | 61 | 62 | 65 | 66 | 67 | 68 | 73 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /app/src/main/assets/web/css/login.css: -------------------------------------------------------------------------------- 1 | .sec_body { color:#404040;background:#EBEBEB;text-shadow:#ddd 0 1px 0px;font-family:Helvetica;line-height:1.5;font-size:small; } 2 | .center_father {color:#404040;text-align: center;} 3 | .center_son { margin-right: auto; margin-left: auto; } -------------------------------------------------------------------------------- /app/src/main/assets/web/image/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangmingchuan/CameraMaster/5340823cd85fea2c819b096efaeb7baa27707c46/app/src/main/assets/web/image/logo.png -------------------------------------------------------------------------------- /app/src/main/assets/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | AndServer Sample 8 | 11 | 12 | 13 |
14 |
15 | Login

16 | More, please see the sample code. 17 |
18 | 19 | -------------------------------------------------------------------------------- /app/src/main/assets/web/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Sign In 10 | 11 | 12 | 13 |
14 |

Sign In

15 |
16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 38 | 39 |
Account:  
    
Password:  
    
36 | 37 |
40 |

Account: 123, Password: 123

41 |
42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/OpenReceiver.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.util.Log; 7 | 8 | import camera.cn.cameramaster.ui.MainActivity; 9 | 10 | /** 11 | * 开机 12 | * @packageName: cn.tongue.tonguecamera 13 | * @fileName: OpenReceiver 14 | * @date: 2019/1/28 13:09 15 | * @author: ymc 16 | * @QQ:745612618 17 | */ 18 | 19 | public class OpenReceiver extends BroadcastReceiver { 20 | @Override 21 | public void onReceive(Context context, Intent intent) { 22 | 23 | Log.i("broadCastReceiver","onReceiver..."); 24 | 25 | Intent mBootIntent = new Intent(context, MainActivity.class); 26 | // 必须设置FLAG_ACTIVITY_NEW_TASK 27 | mBootIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 28 | context.startActivity(mBootIntent); 29 | 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/adapter/EffectAdapter.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.NonNull; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.util.Log; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.TextView; 11 | 12 | import butterknife.BindView; 13 | import butterknife.ButterKnife; 14 | import camera.cn.cameramaster.R; 15 | 16 | /** 17 | * effect 适配器 18 | * 19 | * @packageName: cn.tongue.tonguecamera.adapter 20 | * @fileName: EffectAdapter 21 | * @date: 2019/4/17 14:33 22 | * @author: ymc 23 | * @QQ:745612618 24 | */ 25 | 26 | public class EffectAdapter extends RecyclerView.Adapter { 27 | private LayoutInflater mLayoutInflater; 28 | private String[] effectArr; 29 | 30 | public EffectAdapter(Context mContext,String[] arr) { 31 | this.effectArr = arr; 32 | mLayoutInflater = LayoutInflater.from(mContext); 33 | } 34 | 35 | @NonNull 36 | @Override 37 | public EffectViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 38 | return new EffectViewHolder(mLayoutInflater.inflate(R.layout.item_rv_text, parent, false)); 39 | } 40 | 41 | @Override 42 | public void onBindViewHolder(@NonNull EffectViewHolder holder, int position) { 43 | holder.mTextView.setText(effectArr[position]); 44 | } 45 | 46 | @Override 47 | public int getItemCount() { 48 | return effectArr.length; 49 | } 50 | 51 | public class EffectViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { 52 | @BindView(R.id.text_view) 53 | TextView mTextView; 54 | 55 | EffectViewHolder(View view) { 56 | super(view); 57 | ButterKnife.bind(this, view); 58 | view.setOnClickListener(this); 59 | } 60 | 61 | @Override 62 | public void onClick(View v) { 63 | if (effectOnItemClickListener != null) { 64 | effectOnItemClickListener.itemOnClick(getPosition()); 65 | } 66 | } 67 | } 68 | 69 | private EffectOnItemClickListener effectOnItemClickListener; 70 | 71 | public interface EffectOnItemClickListener { 72 | 73 | void itemOnClick(int position); 74 | 75 | } 76 | 77 | public void setEffectOnItemClickListener(EffectOnItemClickListener effectOnItemClickListener) { 78 | this.effectOnItemClickListener = effectOnItemClickListener; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/adapter/MenuAdapter.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.adapter; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.support.annotation.NonNull; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.util.TypedValue; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.TextView; 12 | 13 | import java.util.List; 14 | 15 | import camera.cn.cameramaster.R; 16 | import camera.cn.cameramaster.view.AutoLocateHorizontalView; 17 | 18 | /** 19 | * 选项适配器 20 | * 21 | * @author ymc 22 | * @date 2019年5月8日 10:38:54 23 | */ 24 | 25 | public class MenuAdapter extends RecyclerView.Adapter 26 | implements AutoLocateHorizontalView.IAutoLocateHorizontalView { 27 | private Context context; 28 | private View view; 29 | private List ages; 30 | private AutoLocateHorizontalView recyclerView; 31 | 32 | public MenuAdapter(Context context, List ages, AutoLocateHorizontalView recyclerView){ 33 | this.context = context; 34 | this.ages = ages; 35 | this.recyclerView = recyclerView; 36 | } 37 | 38 | @NonNull 39 | @Override 40 | public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 41 | view = LayoutInflater.from(context).inflate(R.layout.item_age,parent,false); 42 | return new ItemViewHolder(view); 43 | } 44 | 45 | @Override 46 | public void onBindViewHolder(@NonNull ItemViewHolder holder, int position) { 47 | holder.tvAge.setText(ages.get(position)); 48 | } 49 | 50 | @Override 51 | public int getItemCount() { 52 | return ages.size(); 53 | } 54 | 55 | @Override 56 | public View getItemView() { 57 | return view; 58 | } 59 | 60 | @Override 61 | public void onViewSelected(boolean isSelected, int pos, RecyclerView.ViewHolder holder, int itemWidth) { 62 | if(isSelected) { 63 | ((ItemViewHolder) holder).tvAge.setTextSize(TypedValue.COMPLEX_UNIT_SP,16); 64 | ((ItemViewHolder) holder).tvAge.setTextColor(Color.WHITE); 65 | ((ItemViewHolder) holder).tvAge.setAlpha(1.0f); 66 | }else{ 67 | ((ItemViewHolder) holder).tvAge.setTextSize(TypedValue.COMPLEX_UNIT_SP,14); 68 | ((ItemViewHolder) holder).tvAge.setTextColor(Color.rgb(0xfe,0xfe,0xfe)); 69 | ((ItemViewHolder) holder).tvAge.setAlpha(0.5f); 70 | } 71 | } 72 | 73 | class ItemViewHolder extends RecyclerView.ViewHolder{ 74 | TextView tvAge; 75 | ItemViewHolder(View itemView) { 76 | super(itemView); 77 | tvAge = itemView.findViewById(R.id.tv_age); 78 | tvAge.setTag(this); 79 | tvAge.setOnClickListener(new View.OnClickListener() { 80 | @Override 81 | public void onClick(View v) { 82 | ItemViewHolder itemViewHolder = (ItemViewHolder)v.getTag(); 83 | int position = recyclerView.getChildAdapterPosition(itemViewHolder.itemView); 84 | position--; 85 | recyclerView.moveToPosition(position); 86 | } 87 | }); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/adapter/SenseAdapter.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.NonNull; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.util.Log; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.TextView; 11 | 12 | import butterknife.BindView; 13 | import butterknife.ButterKnife; 14 | import camera.cn.cameramaster.R; 15 | 16 | /** 17 | * effect 适配器 18 | * 19 | * @packageName: cn.tongue.tonguecamera.adapter 20 | * @fileName: EffectAdapter 21 | * @date: 2019/4/17 14:33 22 | * @author: ymc 23 | * @QQ:745612618 24 | */ 25 | 26 | public class SenseAdapter extends RecyclerView.Adapter { 27 | private LayoutInflater mLayoutInflater; 28 | private String[] senseArr; 29 | 30 | public SenseAdapter(Context mContext,String[] arr) { 31 | this.senseArr = arr; 32 | mLayoutInflater = LayoutInflater.from(mContext); 33 | } 34 | 35 | @NonNull 36 | @Override 37 | public EffectViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 38 | return new EffectViewHolder(mLayoutInflater.inflate(R.layout.item_rv_text, parent, false)); 39 | } 40 | 41 | @Override 42 | public void onBindViewHolder(@NonNull EffectViewHolder holder, int position) { 43 | holder.mTextView.setText(senseArr[position]); 44 | } 45 | 46 | @Override 47 | public int getItemCount() { 48 | return senseArr.length; 49 | } 50 | 51 | public class EffectViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { 52 | @BindView(R.id.text_view) 53 | TextView mTextView; 54 | 55 | EffectViewHolder(View view) { 56 | super(view); 57 | ButterKnife.bind(this, view); 58 | view.setOnClickListener(this); 59 | } 60 | 61 | @Override 62 | public void onClick(View v) { 63 | if (senseOnItemClickListener != null) { 64 | senseOnItemClickListener.itemOnClick(getPosition()); 65 | } 66 | } 67 | } 68 | 69 | private SenseOnItemClickListener senseOnItemClickListener; 70 | 71 | public interface SenseOnItemClickListener { 72 | 73 | void itemOnClick(int position); 74 | 75 | } 76 | 77 | public void setSenseOnItemClickListener(SenseOnItemClickListener senseOnItemClickListener) { 78 | this.senseOnItemClickListener = senseOnItemClickListener; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/base/App.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Yan Zhenjie. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package camera.cn.cameramaster.base; 17 | 18 | import android.app.Application; 19 | import android.content.Context; 20 | import android.os.Environment; 21 | import android.support.annotation.NonNull; 22 | 23 | import com.yanzhenjie.andserver.util.IOUtils; 24 | 25 | import java.io.File; 26 | 27 | import camera.cn.cameramaster.server.util.FileUtils; 28 | 29 | 30 | /** 31 | * application 32 | * 33 | * Created by YanZhenjie on 2018/6/9. 34 | * @author ymc 35 | */ 36 | 37 | public class App extends Application { 38 | 39 | private static App mInstance; 40 | 41 | private File mRootDir; 42 | 43 | @Override 44 | public void onCreate() { 45 | super.onCreate(); 46 | 47 | if (mInstance == null) { 48 | mInstance = this; 49 | initRootPath(this); 50 | } 51 | } 52 | 53 | @NonNull 54 | public static App getInstance() { 55 | return mInstance; 56 | } 57 | 58 | @NonNull 59 | public File getRootDir() { 60 | return mRootDir; 61 | } 62 | 63 | private void initRootPath(Context context) { 64 | if (mRootDir != null) { 65 | return; 66 | } 67 | 68 | if (FileUtils.storageAvailable()) { 69 | mRootDir = Environment.getExternalStorageDirectory(); 70 | } else { 71 | mRootDir = context.getFilesDir(); 72 | } 73 | mRootDir = new File(mRootDir, "AndServer"); 74 | IOUtils.createFolder(mRootDir); 75 | } 76 | } -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/base/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.base; 2 | 3 | import android.os.Build; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.view.ViewCompat; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.view.Window; 11 | import android.view.WindowManager; 12 | 13 | import butterknife.ButterKnife; 14 | import butterknife.Unbinder; 15 | import camera.cn.cameramaster.R; 16 | 17 | /** 18 | * 基础Activity 19 | * 20 | * @packageName: cn.ymc.vip.suntimejava.base 21 | * @fileName: BaseActivity 22 | * @date: 2019/1/8 17:35 23 | * @author: ymc 24 | * @QQ:745612618 25 | */ 26 | 27 | public abstract class BaseActivity extends AppCompatActivity { 28 | 29 | protected BaseActivity activity; 30 | private Unbinder bun; 31 | 32 | @Override 33 | protected void onCreate(@Nullable Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | //去除标题栏 36 | supportRequestWindowFeature(Window.FEATURE_NO_TITLE); 37 | //去除状态栏 38 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 39 | WindowManager.LayoutParams.FLAG_FULLSCREEN); 40 | setContentView(getLayoutId()); 41 | // getSupportActionBar().hide(); 42 | bun = ButterKnife.bind(this); 43 | activity = this; 44 | initStatusColor(); 45 | initView(); 46 | initData(); 47 | } 48 | 49 | /** 50 | * 设置透明状态栏,这样才能让 ContentView 向上 6.0小米手机设置 tootlbar 会被挤上去 51 | * window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 52 | */ 53 | private void initStatusColor() { 54 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){ 55 | Window window = activity.getWindow(); 56 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 57 | //设置状态栏颜色 58 | window.setStatusBarColor(getColor(R.color.theme)); 59 | 60 | ViewGroup mContentView = activity.findViewById(Window.ID_ANDROID_CONTENT); 61 | View mChildView = mContentView.getChildAt(0); 62 | if (mChildView != null) { 63 | //注意不是设置 ContentView 的 FitsSystemWindows, 而是设置 ContentView 的第一个子 View . 使其不为系统 View 预留空间. 64 | ViewCompat.setFitsSystemWindows(mChildView, false); 65 | } 66 | } 67 | } 68 | 69 | protected abstract int getLayoutId(); 70 | protected abstract void initView(); 71 | protected abstract void initData(); 72 | 73 | @Override 74 | protected void onDestroy() { 75 | bun.unbind(); 76 | super.onDestroy(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/bean/Lab.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.bean; 2 | 3 | /** 4 | * lab 实体类 5 | * 6 | * @packageName: cn.tongue.tonguecamera.bean 7 | * @fileName: Lab 8 | * @date: 2019/4/3 13:37 9 | * @author: ymc 10 | * @QQ:745612618 11 | */ 12 | 13 | public class Lab { 14 | 15 | public double L; 16 | public double a; 17 | public double b; 18 | 19 | public double getL() { 20 | return L; 21 | } 22 | 23 | public void setL(double l) { 24 | L = l; 25 | } 26 | 27 | public double getA() { 28 | return a; 29 | } 30 | 31 | public void setA(double a) { 32 | this.a = a; 33 | } 34 | 35 | public double getB() { 36 | return b; 37 | } 38 | 39 | public void setB(double b) { 40 | this.b = b; 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return "Lab l:" + L + " Lab a:" + a + " Lab b:" + b; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/filter/TextureFilter.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.filter; 2 | 3 | import android.content.res.Resources; 4 | import android.graphics.SurfaceTexture; 5 | 6 | import java.nio.ByteBuffer; 7 | 8 | /** 9 | * @packageName: cn.tongue.tonguecamera.filter 10 | * @fileName: TextureFilter 11 | * @date: 2019/3/15 14:40 12 | * @author: ymc 13 | * @QQ:745612618 14 | */ 15 | 16 | public class TextureFilter extends AFilter{ 17 | private int width=0; 18 | private int height=0; 19 | 20 | private int[] fFrame = new int[1]; 21 | private int[] fTexture = new int[1]; 22 | private int[] mCameraTexture=new int[1]; 23 | 24 | private SurfaceTexture mSurfaceTexture; 25 | private float[] mCoordOM=new float[16]; 26 | /** 27 | * 获取Track数据 28 | */ 29 | private ByteBuffer tBuffer; 30 | 31 | 32 | public TextureFilter(Resources mRes) { 33 | super(mRes); 34 | } 35 | 36 | @Override 37 | protected void onCreate() { 38 | 39 | } 40 | 41 | @Override 42 | protected void onSizeChanged(int width, int height) { 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/server/AnyEventType.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.server; 2 | 3 | /** 4 | * event bus 消息类 5 | * 6 | * @packageName: cn.tongue.tonguecamera.eventbus 7 | * @fileName: AnyEventType 8 | * @date: 2019/4/24 18:36 9 | * @author: ymc 10 | * @QQ:745612618 11 | */ 12 | 13 | public class AnyEventType { 14 | 15 | public AnyEventType(){} 16 | 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/server/CoreService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2018 Yan Zhenjie. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package camera.cn.cameramaster.server; 17 | 18 | import android.app.Service; 19 | import android.content.Intent; 20 | import android.os.IBinder; 21 | import android.support.annotation.Nullable; 22 | import android.util.Log; 23 | 24 | import com.yanzhenjie.andserver.AndServer; 25 | import com.yanzhenjie.andserver.Server; 26 | 27 | import java.util.concurrent.TimeUnit; 28 | 29 | import camera.cn.cameramaster.server.util.NetUtils; 30 | 31 | 32 | /** 33 | * server 34 | * 35 | * Created by Yan Zhenjie on 2018/6/9. 36 | * @author ymc 37 | */ 38 | public class CoreService extends Service { 39 | private static final String TAG = "CoreService"; 40 | private Server mServer; 41 | 42 | @Override 43 | public void onCreate() { 44 | mServer = AndServer.serverBuilder() 45 | .inetAddress(NetUtils.getLocalIPAddress()) 46 | .port(8081) 47 | .timeout(10, TimeUnit.SECONDS) 48 | .listener(new Server.ServerListener() { 49 | @Override 50 | public void onStarted() { 51 | String hostAddress = mServer.getInetAddress().getHostAddress(); 52 | ServerManager.onServerStart(CoreService.this, hostAddress); 53 | Log.e(TAG, "onStarted: "); 54 | } 55 | 56 | @Override 57 | public void onStopped() { 58 | ServerManager.onServerStop(CoreService.this); 59 | Log.e(TAG, "onStopped: "); 60 | } 61 | 62 | @Override 63 | public void onException(Exception e) { 64 | ServerManager.onServerError(CoreService.this, e.getMessage()); 65 | Log.e(TAG, "onException: "); 66 | } 67 | }) 68 | .build(); 69 | } 70 | 71 | @Override 72 | public int onStartCommand(Intent intent, int flags, int startId) { 73 | startServer(); 74 | return START_STICKY; 75 | } 76 | 77 | @Override 78 | public void onDestroy() { 79 | stopServer(); 80 | super.onDestroy(); 81 | } 82 | 83 | /** 84 | * Start server. 85 | */ 86 | private void startServer() { 87 | if (mServer.isRunning()) { 88 | String hostAddress = mServer.getInetAddress().getHostAddress(); 89 | ServerManager.onServerStart(CoreService.this, hostAddress); 90 | } else { 91 | mServer.startup(); 92 | } 93 | } 94 | 95 | /** 96 | * Stop server. 97 | */ 98 | private void stopServer() { 99 | mServer.shutdown(); 100 | } 101 | 102 | @Nullable 103 | @Override 104 | public IBinder onBind(Intent intent) { 105 | return null; 106 | } 107 | } -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/server/ServerManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2018 Yan Zhenjie. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package camera.cn.cameramaster.server; 17 | 18 | import android.content.BroadcastReceiver; 19 | import android.content.Context; 20 | import android.content.Intent; 21 | import android.content.IntentFilter; 22 | import android.os.Build; 23 | import android.support.annotation.RequiresApi; 24 | 25 | import camera.cn.cameramaster.ui.GoogleCameraActivity; 26 | 27 | 28 | /** 29 | * 30 | * Created by Yan Zhenjie on 2018/6/9. 31 | * @author ymc 32 | */ 33 | 34 | public class ServerManager extends BroadcastReceiver { 35 | 36 | private static final String ACTION = "com.yanzhenjie.andserver.receiver"; 37 | 38 | private static final String CMD_KEY = "CMD_KEY"; 39 | private static final String MESSAGE_KEY = "MESSAGE_KEY"; 40 | 41 | private static final int CMD_VALUE_START = 1; 42 | private static final int CMD_VALUE_ERROR = 2; 43 | private static final int CMD_VALUE_STOP = 4; 44 | 45 | /** 46 | * Notify serverStart. 47 | * 48 | * @param context context. 49 | */ 50 | public static void onServerStart(Context context, String hostAddress) { 51 | sendBroadcast(context, CMD_VALUE_START, hostAddress); 52 | } 53 | 54 | /** 55 | * Notify serverStop. 56 | * 57 | * @param context context. 58 | */ 59 | public static void onServerError(Context context, String error) { 60 | sendBroadcast(context, CMD_VALUE_ERROR, error); 61 | } 62 | 63 | /** 64 | * Notify serverStop. 65 | * 66 | * @param context context. 67 | */ 68 | public static void onServerStop(Context context) { 69 | sendBroadcast(context, CMD_VALUE_STOP); 70 | } 71 | 72 | private static void sendBroadcast(Context context, int cmd) { 73 | sendBroadcast(context, cmd, null); 74 | } 75 | 76 | private static void sendBroadcast(Context context, int cmd, String message) { 77 | Intent broadcast = new Intent(ACTION); 78 | broadcast.putExtra(CMD_KEY, cmd); 79 | broadcast.putExtra(MESSAGE_KEY, message); 80 | context.sendBroadcast(broadcast); 81 | } 82 | 83 | private GoogleCameraActivity mActivity; 84 | private Intent mService; 85 | 86 | public ServerManager(GoogleCameraActivity activity) { 87 | this.mActivity = activity; 88 | mService = new Intent(activity, CoreService.class); 89 | } 90 | 91 | /** 92 | * Register broadcast. 93 | */ 94 | public void register() { 95 | IntentFilter filter = new IntentFilter(ACTION); 96 | mActivity.registerReceiver(this, filter); 97 | } 98 | 99 | /** 100 | * UnRegister broadcast. 101 | */ 102 | public void unRegister() { 103 | mActivity.unregisterReceiver(this); 104 | } 105 | 106 | public void startServer() { 107 | mActivity.startService(mService); 108 | } 109 | 110 | public void stopServer() { 111 | mActivity.stopService(mService); 112 | } 113 | 114 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 115 | @Override 116 | public void onReceive(Context context, Intent intent) { 117 | String action = intent.getAction(); 118 | if (ACTION.equals(action)) { 119 | int cmd = intent.getIntExtra(CMD_KEY, 0); 120 | switch (cmd) { 121 | case CMD_VALUE_START: { 122 | String ip = intent.getStringExtra(MESSAGE_KEY); 123 | mActivity.onServerStart(ip); 124 | break; 125 | } 126 | case CMD_VALUE_ERROR: { 127 | String error = intent.getStringExtra(MESSAGE_KEY); 128 | mActivity.onServerError(error); 129 | break; 130 | } 131 | case CMD_VALUE_STOP: { 132 | mActivity.onServerStop(); 133 | break; 134 | } 135 | default: 136 | break; 137 | } 138 | } 139 | } 140 | } -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/server/TestController.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.server; 2 | 3 | import android.os.Build; 4 | import android.support.annotation.RequiresApi; 5 | import android.util.Log; 6 | 7 | import com.alibaba.fastjson.JSON; 8 | import com.yanzhenjie.andserver.annotation.Addition; 9 | import com.yanzhenjie.andserver.annotation.CookieValue; 10 | import com.yanzhenjie.andserver.annotation.FormPart; 11 | import com.yanzhenjie.andserver.annotation.GetMapping; 12 | import com.yanzhenjie.andserver.annotation.PathVariable; 13 | import com.yanzhenjie.andserver.annotation.PostMapping; 14 | import com.yanzhenjie.andserver.annotation.RequestBody; 15 | import com.yanzhenjie.andserver.annotation.RequestMapping; 16 | import com.yanzhenjie.andserver.annotation.RequestParam; 17 | import com.yanzhenjie.andserver.annotation.ResponseBody; 18 | import com.yanzhenjie.andserver.annotation.RestController; 19 | import com.yanzhenjie.andserver.http.HttpRequest; 20 | import com.yanzhenjie.andserver.http.HttpResponse; 21 | import com.yanzhenjie.andserver.http.cookie.Cookie; 22 | import com.yanzhenjie.andserver.http.multipart.MultipartFile; 23 | import com.yanzhenjie.andserver.http.session.Session; 24 | import com.yanzhenjie.andserver.util.MediaType; 25 | 26 | import org.greenrobot.eventbus.EventBus; 27 | 28 | import java.io.File; 29 | import java.io.IOException; 30 | import java.util.List; 31 | 32 | import camera.cn.cameramaster.server.model.UserInfo; 33 | import camera.cn.cameramaster.server.util.FileUtils; 34 | 35 | 36 | /** 37 | * 测试控制器 38 | * 39 | * @packageName: ymc.cn.servertest 40 | * @fileName: TestController 41 | * @date: 2019/4/23 16:15 42 | * @author: ymc 43 | * @QQ:745612618 44 | */ 45 | 46 | @RestController 47 | @RequestMapping(path = "/test") 48 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 49 | public class TestController { 50 | 51 | private static final String TAG = "TestController"; 52 | 53 | private static final String LOGIN_ATTRIBUTE = "USER.LOGIN.SIGN"; 54 | 55 | @ResponseBody 56 | @GetMapping("/take") 57 | public void takeCamera() { 58 | EventBus.getDefault().post(new AnyEventType()); 59 | } 60 | 61 | @GetMapping(path = "/get/{userId}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) 62 | String info(@PathVariable(name = "userId") String userId) { 63 | return userId; 64 | } 65 | 66 | @PostMapping(path = "/login", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) 67 | String login(HttpRequest request, HttpResponse response, @RequestParam(name = "account",required = false 68 | ) String account, @RequestParam(name = "password",required = false) String password) { 69 | Session session = request.getValidSession(); 70 | session.setAttribute(LOGIN_ATTRIBUTE, true); 71 | 72 | Cookie cookie = new Cookie("account", account + "=" + password); 73 | response.addCookie(cookie); 74 | return "login successful"; 75 | } 76 | 77 | @Addition(stringType = "login", booleanType = true) 78 | @GetMapping(path = "/userInfo", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) 79 | UserInfo userInfo(@CookieValue("account") String account) { 80 | Log.e(TAG, "Account: " + account); 81 | UserInfo userInfo = new UserInfo(); 82 | userInfo.setmUserId("123"); 83 | userInfo.setmUserName("AndServer"); 84 | return userInfo; 85 | } 86 | 87 | @PostMapping(path = "/upload", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) 88 | String upload(@RequestParam(name = "header") MultipartFile file) throws IOException { 89 | File localFile = FileUtils.createRandomFile(file); 90 | file.transferTo(localFile); 91 | return localFile.getAbsolutePath(); 92 | } 93 | 94 | @GetMapping(path = "/consume", consumes = {"application/json", "!application/xml"}) 95 | String consume() { 96 | return "Consume is successful"; 97 | } 98 | 99 | @GetMapping(path = "/produce", produces = {"application/json; charset=utf-8"}) 100 | String produce() { 101 | return "Produce is successful"; 102 | } 103 | 104 | @GetMapping(path = "/include", params = {"name=123"}) 105 | String include(@RequestParam(name = "name") String name) { 106 | return name; 107 | } 108 | 109 | @GetMapping(path = "/exclude", params = "name!=123") 110 | String exclude() { 111 | return "Exclude is successful."; 112 | } 113 | 114 | @GetMapping(path = {"/mustKey", "/getName"}, params = "name") 115 | String getMustKey(@RequestParam(name = "name") String name) { 116 | return name; 117 | } 118 | 119 | @PostMapping(path = {"/mustKey", "/postName"}, params = "name") 120 | String postMustKey(@RequestParam(name = "name") String name) { 121 | return name; 122 | } 123 | 124 | @GetMapping(path = "/noName", params = "!name") 125 | String noName() { 126 | return "NoName is successful."; 127 | } 128 | 129 | @PostMapping(path = "/formPart") 130 | String forPart(@FormPart(name = "user") UserInfo userInfo) { 131 | return JSON.toJSONString(userInfo); 132 | } 133 | 134 | @PostMapping(path = "/jsonBody") 135 | String jsonBody(@RequestBody UserInfo userInfo) { 136 | return JSON.toJSONString(userInfo); 137 | } 138 | 139 | @PostMapping(path = "/listBody") 140 | String jsonBody(@RequestBody List infoList) { 141 | return JSON.toJSONString(infoList); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/server/component/LoggerInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Yan Zhenjie. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package camera.cn.cameramaster.server.component; 17 | 18 | import android.support.annotation.NonNull; 19 | import android.util.Log; 20 | 21 | import com.alibaba.fastjson.JSON; 22 | import com.yanzhenjie.andserver.annotation.Interceptor; 23 | import com.yanzhenjie.andserver.framework.HandlerInterceptor; 24 | import com.yanzhenjie.andserver.framework.handler.RequestHandler; 25 | import com.yanzhenjie.andserver.http.HttpMethod; 26 | import com.yanzhenjie.andserver.http.HttpRequest; 27 | import com.yanzhenjie.andserver.http.HttpResponse; 28 | import com.yanzhenjie.andserver.util.MultiValueMap; 29 | 30 | /** 31 | * 拦截器 32 | * 33 | * @author ymc 34 | */ 35 | 36 | @Interceptor 37 | public class LoggerInterceptor implements HandlerInterceptor { 38 | 39 | private static final String TAG = "LoggerInterceptor"; 40 | 41 | @Override 42 | public boolean onIntercept(@NonNull HttpRequest request, @NonNull HttpResponse response, 43 | @NonNull RequestHandler handler) { 44 | String path = request.getPath(); 45 | HttpMethod method = request.getMethod(); 46 | MultiValueMap valueMap = request.getParameter(); 47 | Log.e(TAG, "Path: " + path); 48 | Log.e(TAG, "Method: " + method.value()); 49 | Log.e(TAG, "Param: " + JSON.toJSONString(valueMap)); 50 | return false; 51 | } 52 | } -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/server/model/UserInfo.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.server.model; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | import com.alibaba.fastjson.annotation.JSONField; 7 | 8 | /** 9 | * 用户 10 | * 11 | * @packageName: ymc.cn.servertest.model 12 | * @fileName: UserInfo 13 | * @date: 2019/4/23 17:31 14 | * @author: ymc 15 | * @QQ:745612618 16 | */ 17 | 18 | public class UserInfo implements Parcelable { 19 | 20 | @JSONField(name = "userId") 21 | private String mUserId; 22 | @JSONField(name = "userName") 23 | private String mUserName; 24 | 25 | public static final Creator CREATOR = new Creator() { 26 | @Override 27 | public UserInfo createFromParcel(Parcel in) { 28 | return new UserInfo(in); 29 | } 30 | 31 | @Override 32 | public UserInfo[] newArray(int size) { 33 | return new UserInfo[size]; 34 | } 35 | }; 36 | 37 | @Override 38 | public int describeContents() { 39 | return 0; 40 | } 41 | 42 | @Override 43 | public void writeToParcel(Parcel dest, int flags) { 44 | dest.writeString(mUserId); 45 | dest.writeString(mUserName); 46 | } 47 | 48 | public UserInfo() { 49 | } 50 | 51 | protected UserInfo(Parcel in) { 52 | mUserId = in.readString(); 53 | mUserName = in.readString(); 54 | } 55 | 56 | public String getmUserId() { 57 | return mUserId; 58 | } 59 | 60 | public void setmUserId(String mUserId) { 61 | this.mUserId = mUserId; 62 | } 63 | 64 | public String getmUserName() { 65 | return mUserName; 66 | } 67 | 68 | public void setmUserName(String mUserName) { 69 | this.mUserName = mUserName; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/server/util/FileUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Yan Zhenjie. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package camera.cn.cameramaster.server.util; 17 | 18 | import android.os.Environment; 19 | import android.webkit.MimeTypeMap; 20 | 21 | import com.yanzhenjie.andserver.http.multipart.MultipartFile; 22 | import com.yanzhenjie.andserver.util.StringUtils; 23 | 24 | import java.io.File; 25 | import java.util.UUID; 26 | 27 | import camera.cn.cameramaster.base.App; 28 | 29 | 30 | /** 31 | * Created by YanZhenjie on 2018/6/9. 32 | */ 33 | public class FileUtils { 34 | 35 | /** 36 | * Create a random file based on mimeType. 37 | * 38 | * @param file file. 39 | * 40 | * @return file object. 41 | */ 42 | public static File createRandomFile(MultipartFile file) { 43 | String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(file.getContentType().toString()); 44 | if (StringUtils.isEmpty(extension)) { 45 | extension = MimeTypeMap.getFileExtensionFromUrl(file.getFilename()); 46 | } 47 | String uuid = UUID.randomUUID().toString(); 48 | return new File(App.getInstance().getRootDir(), uuid + "." + extension); 49 | } 50 | 51 | /** 52 | * SD is available. 53 | * 54 | * @return true, otherwise is false. 55 | */ 56 | public static boolean storageAvailable() { 57 | if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 58 | File sd = new File(Environment.getExternalStorageDirectory().getAbsolutePath()); 59 | return sd.canWrite(); 60 | } else { 61 | return false; 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/server/util/NetUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2018 Yan Zhenjie. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package camera.cn.cameramaster.server.util; 17 | 18 | import java.net.InetAddress; 19 | import java.net.NetworkInterface; 20 | import java.net.SocketException; 21 | import java.util.Enumeration; 22 | import java.util.regex.Pattern; 23 | 24 | /** 25 | * Created by YanZhenjie on 2018/6/9. 26 | */ 27 | public class NetUtils { 28 | 29 | /** 30 | * Ipv4 address check. 31 | */ 32 | private static final Pattern IPV4_PATTERN = Pattern.compile( 33 | "^(" + "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}" + 34 | "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"); 35 | 36 | /** 37 | * Check if valid IPV4 address. 38 | * 39 | * @param input the address string to check for validity. 40 | * 41 | * @return True if the input parameter is a valid IPv4 address. 42 | */ 43 | public static boolean isIPv4Address(String input) { 44 | return IPV4_PATTERN.matcher(input).matches(); 45 | } 46 | 47 | /** 48 | * Get local Ip address. 49 | */ 50 | public static InetAddress getLocalIPAddress() { 51 | Enumeration enumeration = null; 52 | try { 53 | enumeration = NetworkInterface.getNetworkInterfaces(); 54 | } catch (SocketException e) { 55 | e.printStackTrace(); 56 | } 57 | if (enumeration != null) { 58 | while (enumeration.hasMoreElements()) { 59 | NetworkInterface nif = enumeration.nextElement(); 60 | Enumeration inetAddresses = nif.getInetAddresses(); 61 | if (inetAddresses != null) { 62 | while (inetAddresses.hasMoreElements()) { 63 | InetAddress inetAddress = inetAddresses.nextElement(); 64 | if (!inetAddress.isLoopbackAddress() && isIPv4Address(inetAddress.getHostAddress())) { 65 | return inetAddress; 66 | } 67 | } 68 | } 69 | } 70 | } 71 | return null; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/ui/CameraSurfaceViewActivity.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.ui; 2 | 3 | import android.os.Build; 4 | import android.support.annotation.RequiresApi; 5 | import android.support.constraint.ConstraintLayout; 6 | import android.util.DisplayMetrics; 7 | import android.util.Log; 8 | import android.util.Size; 9 | import android.view.View; 10 | import android.widget.FrameLayout; 11 | import android.widget.LinearLayout; 12 | 13 | import butterknife.BindView; 14 | import butterknife.OnClick; 15 | import camera.cn.cameramaster.R; 16 | import camera.cn.cameramaster.base.BaseActivity; 17 | import camera.cn.cameramaster.util.CameraV2; 18 | import camera.cn.cameramaster.view.CameraV2GLSurfaceView; 19 | 20 | /** 21 | * 基于 camera2 surfaceview 过滤界面 22 | * 参考url : [https://blog.csdn.net/lb377463323/article/details/78054892] 23 | * 24 | * @author ymc 25 | * @date 2019年2月12日 14:32:37 26 | */ 27 | 28 | public class CameraSurfaceViewActivity extends BaseActivity { 29 | private static final String TAG = "CameraSVActivity"; 30 | @BindView(R.id.frame_layout) 31 | FrameLayout frameLayout; 32 | private CameraV2 mCamera; 33 | private CameraV2GLSurfaceView mCameraV2GLSurfaceView; 34 | 35 | @Override 36 | protected int getLayoutId() { 37 | return R.layout.activity_camera_sv; 38 | } 39 | 40 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 41 | @Override 42 | protected void initView() { 43 | mCameraV2GLSurfaceView = new CameraV2GLSurfaceView(this); 44 | DisplayMetrics dm = new DisplayMetrics(); 45 | getWindowManager().getDefaultDisplay().getMetrics(dm); 46 | mCamera = new CameraV2(this); 47 | Size size = mCamera.setUpCameraOutputs(dm.widthPixels, dm.heightPixels); 48 | if (!mCamera.openCamera()) { 49 | Log.e(TAG, "mCamera openCamera err"); 50 | return; 51 | } 52 | mCameraV2GLSurfaceView.init(mCamera, false, 53 | CameraSurfaceViewActivity.this); 54 | // 将 surfaceview 添加到布局中 55 | ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams( 56 | LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); 57 | lp.width = size.getHeight(); 58 | lp.height = size.getWidth(); 59 | mCameraV2GLSurfaceView.setLayoutParams(lp); 60 | frameLayout.addView(mCameraV2GLSurfaceView); 61 | } 62 | 63 | @Override 64 | protected void initData() { 65 | 66 | } 67 | 68 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 69 | @OnClick({R.id.iv_back, R.id.img_camera}) 70 | public void onClick(View view) { 71 | switch (view.getId()) { 72 | case R.id.iv_back: 73 | finish(); 74 | break; 75 | case R.id.img_camera: 76 | mCamera.lockFocus(); 77 | break; 78 | default: 79 | break; 80 | } 81 | } 82 | 83 | // TODO: 2019/4/3 会退到当前界面如何重新启动相机 84 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 85 | @Override 86 | protected void onResume() { 87 | super.onResume(); 88 | mCamera.startBackgroundThread(); 89 | // 存在关联则打开相机,没有则绑定事件 90 | // mCamera.openCamera(); 91 | } 92 | 93 | @Override 94 | protected void onPause() { 95 | mCamera.closeCamera(); 96 | mCamera.stopBackgroundThread(); 97 | super.onPause(); 98 | } 99 | 100 | @Override 101 | protected void onDestroy() { 102 | super.onDestroy(); 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/ui/MainActivity.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.ui; 2 | 3 | import android.Manifest; 4 | import android.annotation.SuppressLint; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.net.ConnectivityManager; 8 | import android.os.Build; 9 | import android.support.annotation.RequiresApi; 10 | import android.util.Log; 11 | import android.view.View; 12 | import android.widget.Button; 13 | import android.widget.TextView; 14 | 15 | import com.yanzhenjie.permission.Action; 16 | import com.yanzhenjie.permission.AndPermission; 17 | import com.yanzhenjie.permission.Rationale; 18 | import com.yanzhenjie.permission.RequestExecutor; 19 | 20 | import java.io.File; 21 | import java.lang.reflect.Method; 22 | import java.util.List; 23 | 24 | import butterknife.BindView; 25 | import butterknife.OnClick; 26 | import camera.cn.cameramaster.R; 27 | import camera.cn.cameramaster.base.BaseActivity; 28 | import camera.cn.cameramaster.util.AppConstant; 29 | 30 | /** 31 | * 首页 32 | * 33 | * @author ymc 34 | */ 35 | 36 | public class MainActivity extends BaseActivity { 37 | private final static String TAG = "MainActivity"; 38 | @BindView(R.id.btn_camera) 39 | public Button btn; 40 | @BindView(R.id.tv_message) 41 | TextView tvMsg; 42 | 43 | private File mD65File; 44 | private File mFile; 45 | 46 | @Override 47 | protected int getLayoutId() { 48 | return R.layout.activity_main; 49 | } 50 | 51 | @Override 52 | protected void initView() { 53 | mD65File = new File(getExternalFilesDir(""), "picD65.jpg"); 54 | mFile = new File(getExternalFilesDir(null), "pic.jpg"); 55 | } 56 | 57 | @Override 58 | protected void initData() { 59 | requestPermission(); 60 | // 设置关闭 移动网络 61 | setDataConnectionState(this,false); 62 | } 63 | 64 | 65 | @SuppressLint("WrongConstant") 66 | public static void setDataConnectionState(Context cxt, boolean state) { 67 | ConnectivityManager connectivityManager = null; 68 | Class connectivityManagerClz = null; 69 | try { 70 | connectivityManager = (ConnectivityManager) cxt 71 | .getSystemService("connectivity"); 72 | connectivityManagerClz = connectivityManager.getClass(); 73 | Method method = connectivityManagerClz.getMethod( 74 | "setMobileDataEnabled", new Class[] { boolean.class }); 75 | method.invoke(connectivityManager, state); 76 | } catch (Exception e) { 77 | e.printStackTrace(); 78 | } 79 | } 80 | 81 | @OnClick({R.id.btn_camera, R.id.btn_camera2, R.id.btn_filter_camera2, R.id.btn_camera2_video}) 82 | public void onClick(View view) { 83 | switch (view.getId()) { 84 | case R.id.btn_camera: 85 | Intent intent = new Intent(this, CameraActivity.class); 86 | startActivityForResult(intent, 0); 87 | break; 88 | case R.id.btn_camera2: 89 | Intent intent2 = new Intent(this, GoogleCameraActivity.class); 90 | startActivityForResult(intent2, 1); 91 | break; 92 | case R.id.btn_filter_camera2: 93 | Intent intentFilter2 = new Intent(this, CameraSurfaceViewActivity.class); 94 | startActivityForResult(intentFilter2, 0); 95 | break; 96 | case R.id.btn_camera2_video: 97 | Intent intentVideo = new Intent(this, CameraVideoActivity.class); 98 | startActivity(intentVideo); 99 | break; 100 | default: 101 | break; 102 | } 103 | } 104 | 105 | 106 | @Override 107 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 108 | super.onActivityResult(requestCode, resultCode, data); 109 | if (resultCode != AppConstant.RESULT_CODE.RESULT_OK) { 110 | return; 111 | } 112 | if (requestCode == 0) { 113 | String imgPath = data.getStringExtra(AppConstant.KEY.IMG_PATH); 114 | int picWidth = data.getIntExtra(AppConstant.KEY.PIC_WIDTH, 0); 115 | int picHeight = data.getIntExtra(AppConstant.KEY.PIC_HEIGHT, 0); 116 | Intent intent = new Intent(activity, ShowPicActivity.class); 117 | intent.putExtra(AppConstant.KEY.PIC_WIDTH, picWidth); 118 | intent.putExtra(AppConstant.KEY.PIC_HEIGHT, picHeight); 119 | intent.putExtra(AppConstant.KEY.IMG_PATH, imgPath); 120 | startActivity(intent); 121 | } else if (requestCode == 1) { 122 | // tvMsg.setText("图片 D65 光源处理中 请勿退出...."); 123 | // new Thread(new Runnable() { 124 | // @Override 125 | // public void run() { 126 | // final long starttime = System.currentTimeMillis(); 127 | // FileInputStream fis = null; 128 | // FileOutputStream output = null; 129 | // try { 130 | // fis = new FileInputStream(mFile); 131 | // Bitmap bitmap = BitmapFactory.decodeStream(fis); 132 | // Bitmap d65bitmap = BitmapUtils.ImgaeToNegative(bitmap); 133 | // output = new FileOutputStream(mD65File); 134 | // d65bitmap.compress(Bitmap.CompressFormat.JPEG, 100, output); 135 | // runOnUiThread(new Runnable() { 136 | // @Override 137 | // public void run() { 138 | // tvMsg.setText("处理完毕.耗时:"+ (System.currentTimeMillis() - starttime)+ " ms"); 139 | // } 140 | // }); 141 | // } catch (FileNotFoundException e) { 142 | // e.printStackTrace(); 143 | // } 144 | // } 145 | // }).start(); 146 | } 147 | } 148 | 149 | /** 150 | * 动态申请 (电话/位置/存储) 151 | */ 152 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN) 153 | private void requestPermission() { 154 | AndPermission.with(this) 155 | .permission(Manifest.permission.CAMERA, 156 | Manifest.permission.READ_EXTERNAL_STORAGE, 157 | Manifest.permission.RECORD_AUDIO) 158 | .rationale(new Rationale() { 159 | @Override 160 | public void showRationale(Context context, List permissions, RequestExecutor executor) { 161 | executor.execute(); 162 | } 163 | }) 164 | .onGranted(new Action() { 165 | @Override 166 | public void onAction(List permissions) { 167 | Log.e(TAG, "用户给权限"); 168 | } 169 | }) 170 | .onDenied(new Action() { 171 | @Override 172 | public void onAction(List permissions) { 173 | if (AndPermission.hasAlwaysDeniedPermission(MainActivity.this, permissions)) { 174 | // 打开权限设置页 175 | AndPermission.permissionSetting(MainActivity.this).execute(); 176 | return; 177 | } 178 | Log.e(TAG, "用户拒绝权限"); 179 | } 180 | }) 181 | .start(); 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/util/AppConstant.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.util; 2 | 3 | /** 4 | * 应用 常量类 5 | * 6 | * @packageName: cn.ymc.suncamera.util 7 | * @fileName: AppConstant 8 | * @date: 2019/1/24 16:54 9 | * @author: ymc 10 | * @QQ:745612618 11 | */ 12 | 13 | public class AppConstant { 14 | 15 | /** 16 | * 摄像头模式 17 | */ 18 | public final static int CAMERA_MODE = 0; 19 | /** 20 | * 视频播放器模式 21 | */ 22 | public final static int VIDEO_MODE = 1; 23 | 24 | /** 25 | * 视频最长的时长是10s 26 | */ 27 | public final static int VIDEO_MAX_TIME = 10; 28 | 29 | /** 30 | * 视频播放模式 31 | */ 32 | public final static int VIDEO_PLAY_MODE = 0; 33 | 34 | /** 35 | * 视频录像模式 36 | */ 37 | public final static int VIDEO_RECORD_MODE = 1; 38 | 39 | /** 40 | * 拍照模式 41 | */ 42 | public final static int VIDEO_TAKE_PHOTO = 2; 43 | 44 | /** 45 | * 当前面板是预览状态 46 | */ 47 | public final static int TEXTURE_PREVIEW_STATE = 0; 48 | 49 | /** 50 | * 当前面板是录像状态 51 | */ 52 | public final static int TEXTURE_RECORD_STATE = 1; 53 | 54 | /** 55 | * 当前面板是图片状态 56 | */ 57 | public final static int TEXTURE_PHOTO_STATE = 2; 58 | 59 | /** 60 | * 当前面板是视频播放状态 61 | */ 62 | 63 | public final static int TEXTURE_PLAY_STATE = 3; 64 | 65 | /** 66 | * 当前是摄像头模式还是视频播放模式 67 | */ 68 | public int MODE; 69 | 70 | /** 71 | * 当前的模式,默认为拍照模式 72 | */ 73 | public int NOW_MODE = VIDEO_TAKE_PHOTO; 74 | 75 | 76 | /** 77 | * 感觉数组 78 | */ 79 | public static String[] senseArr = {"DISABLED", "FACE_PRIORITY", "ACTION", "PORTRAIT", "LANDSCAPE", "NIGHT" 80 | , "NIGHT_PORTRAIT", "THEATRE", "BEACH", "SNOW", "SUNSET", "STEADYPHOTO", "FIREWORKS", 81 | "SPORTS", "PARTY", "CANDLELIGHT", "BARCODE"}; 82 | 83 | public static String[] effectArr = {"aqua", "blackboard", "monoColor", "negative", "posterization", "sepia" 84 | , "solarisation", "whiteboard", "off"}; 85 | 86 | public interface KEY{ 87 | String IMG_PATH = "IMG_PATH"; 88 | String VIDEO_PATH = "VIDEO_PATH"; 89 | String PIC_WIDTH = "PIC_WIDTH"; 90 | String PIC_HEIGHT = "PIC_HEIGHT"; 91 | } 92 | 93 | public interface RESULT_CODE { 94 | int RESULT_OK = -1; 95 | int RESULT_CANCELED = 0; 96 | int RESULT_ERROR = 1; 97 | } 98 | 99 | /** 100 | * 底部状态 : 曝光 101 | */ 102 | public static final int SHOW_AE = 1; 103 | /** 104 | * 白平衡 105 | */ 106 | public static final int SHOW_AWB = 2; 107 | /** 108 | * 感光度 109 | */ 110 | public static final int SHOW_ISO = 3; 111 | /** 112 | * 放大 倍数 113 | */ 114 | public static final int SHOW_ZOOM = 4; 115 | /** 116 | * effect 117 | */ 118 | public static final int SHOW_EFFECT = 5; 119 | /** 120 | * sense 121 | */ 122 | public static final int SHOW_SENSE = 6; 123 | 124 | /** 125 | * 手动设置 126 | */ 127 | public static final int SHOW_SETTING = 6; 128 | 129 | 130 | /** 131 | * lab rgb 数组 132 | */ 133 | public static double[][] labmap = {{37.986,13.555,14.059},{65.711,18.13,17.81},{49.927,-4.88,-21.925}, 134 | {43.139,-13.095,21.905} ,{55.112,8.844,-25.399},{70.719,-33.397,-0.199}, 135 | {62.661,36.067,57.096},{40.02,10.41,-45.964},{51.124,48.239,16.248}, 136 | {30.325,22.976,-21.587},{72.532,-23.709,57.255},{71.941,19.363,67.857}, 137 | {28.778,14.179,-50.297},{55.261,-38.342,31.37},{42.101,53.378,28.19}, 138 | {81.733,4.039,79.819} ,{51.935,49.986,-14.574},{51.038,-28.631,-28.638}, 139 | {96.539,-0.425,1.186},{81.257,-0.638,-0.335},{66.766,-0.734,-0.504}, 140 | {50.867,-0.153,-0.27} ,{35.656,-0.421,-1.231},{20.461,-0.079,-0.973}}; 141 | 142 | public static double [][] rgbmap = {{115,82,68},{194,150,130},{98,122,157},{87,108,67}, 143 | {133,128,177},{103,189,170},{214,126,44},{80,91,166},{193,90,99},{94,60,108}, 144 | {157,188,64},{224,163,46},{56,61,150},{70,148,73},{175,54,60},{231,199,31}, 145 | {187,86,149},{8,133,161},{243,243,242},{200,200,200},{160,160,160}, 146 | {122,122,121},{85,85,85},{52,52,52}}; 147 | 148 | } 149 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/util/Camera2Util.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.util; 2 | 3 | import android.graphics.ImageFormat; 4 | import android.media.Image; 5 | import android.os.Build; 6 | import android.support.annotation.RequiresApi; 7 | import android.util.Log; 8 | 9 | import java.nio.ByteBuffer; 10 | 11 | /** 12 | * camera2 中 yuv 420 格式图片 转为 rgb 图片 13 | * 14 | * @packageName: cn.tongue.tonguecamera.util 15 | * @fileName: Camera2Util 16 | * @date: 2019/3/13 13:37 17 | * @author: ymc 18 | * @QQ:745612618 19 | */ 20 | 21 | public class Camera2Util { 22 | 23 | public static final int YUV420P = 0; 24 | public static final int YUV420SP = 1; 25 | public static final int NV21 = 2; 26 | private static final String TAG = "Camera2Util"; 27 | 28 | /*** 29 | * 此方法内注释以640*480为例 30 | * 未考虑CropRect的 31 | */ 32 | @RequiresApi(api = Build.VERSION_CODES.KITKAT) 33 | public static byte[] getBytesFromImageAsType(Image image, int type) { 34 | try { 35 | //获取源数据,如果是YUV格式的数据planes.length = 3 36 | //plane[i]里面的实际数据可能存在byte[].length <= capacity (缓冲区总大小) 37 | final Image.Plane[] planes = image.getPlanes(); 38 | //数据有效宽度,一般的,图片width <= rowStride,这也是导致byte[].length <= capacity的原因 39 | // 所以我们只取width部分 40 | int width = image.getWidth(); 41 | int height = image.getHeight(); 42 | 43 | //此处用来装填最终的YUV数据,需要1.5倍的图片大小,因为Y U V 比例为 4:1:1 44 | byte[] yuvBytes = new byte[width * height * ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8]; 45 | //目标数组的装填到的位置 46 | int dstIndex = 0; 47 | 48 | //临时存储uv数据的 49 | byte uBytes[] = new byte[width * height / 4]; 50 | byte vBytes[] = new byte[width * height / 4]; 51 | int uIndex = 0; 52 | int vIndex = 0; 53 | 54 | int pixelsStride, rowStride; 55 | for (int i = 0; i < planes.length; i++) { 56 | pixelsStride = planes[i].getPixelStride(); 57 | rowStride = planes[i].getRowStride(); 58 | 59 | ByteBuffer buffer = planes[i].getBuffer(); 60 | 61 | //如果pixelsStride==2,一般的Y的buffer长度=640*480,UV的长度=640*480/2-1 62 | //源数据的索引,y的数据是byte中连续的,u的数据是v向左移以为生成的,两者都是偶数位为有效数据 63 | byte[] bytes = new byte[buffer.capacity()]; 64 | buffer.get(bytes); 65 | 66 | int srcIndex = 0; 67 | if (i == 0) { 68 | //直接取出来所有Y的有效区域,也可以存储成一个临时的bytes,到下一步再copy 69 | for (int j = 0; j < height; j++) { 70 | System.arraycopy(bytes, srcIndex, yuvBytes, dstIndex, width); 71 | srcIndex += rowStride; 72 | dstIndex += width; 73 | } 74 | } else if (i == 1) { 75 | //根据pixelsStride取相应的数据 76 | for (int j = 0; j < height / 2; j++) { 77 | for (int k = 0; k < width / 2; k++) { 78 | uBytes[uIndex++] = bytes[srcIndex]; 79 | srcIndex += pixelsStride; 80 | } 81 | if (pixelsStride == 2) { 82 | srcIndex += rowStride - width; 83 | } else if (pixelsStride == 1) { 84 | srcIndex += rowStride - width / 2; 85 | } 86 | } 87 | } else if (i == 2) { 88 | //根据pixelsStride取相应的数据 89 | for (int j = 0; j < height / 2; j++) { 90 | for (int k = 0; k < width / 2; k++) { 91 | vBytes[vIndex++] = bytes[srcIndex]; 92 | srcIndex += pixelsStride; 93 | } 94 | if (pixelsStride == 2) { 95 | srcIndex += rowStride - width; 96 | } else if (pixelsStride == 1) { 97 | srcIndex += rowStride - width / 2; 98 | } 99 | } 100 | } 101 | } 102 | // image.close(); 103 | //根据要求的结果类型进行填充 104 | switch (type) { 105 | case YUV420P: 106 | System.arraycopy(uBytes, 0, yuvBytes, dstIndex, uBytes.length); 107 | System.arraycopy(vBytes, 0, yuvBytes, dstIndex + uBytes.length, vBytes.length); 108 | break; 109 | case YUV420SP: 110 | for (int i = 0; i < vBytes.length; i++) { 111 | yuvBytes[dstIndex++] = uBytes[i]; 112 | yuvBytes[dstIndex++] = vBytes[i]; 113 | } 114 | break; 115 | case NV21: 116 | for (int i = 0; i < vBytes.length; i++) { 117 | yuvBytes[dstIndex++] = vBytes[i]; 118 | yuvBytes[dstIndex++] = uBytes[i]; 119 | } 120 | break; 121 | } 122 | return yuvBytes; 123 | } catch (final Exception e) { 124 | if (image != null) { 125 | image.close(); 126 | } 127 | Log.i(TAG, e.toString()); 128 | } 129 | return null; 130 | } 131 | 132 | /*** 133 | * YUV420 转化成 RGB 134 | */ 135 | public static int[] decodeYUV420SP(byte[] yuv420sp, int width, int height) { 136 | final int frameSize = width * height; 137 | int rgb[] = new int[frameSize]; 138 | for (int j = 0, yp = 0; j < height; j++) { 139 | int uvp = frameSize + (j >> 1) * width, u = 0, v = 0; 140 | for (int i = 0; i < width; i++, yp++) { 141 | int y = (0xff & ((int) yuv420sp[yp])) - 16; 142 | if (y < 0) { 143 | y = 0; 144 | } 145 | if ((i & 1) == 0) { 146 | v = (0xff & yuv420sp[uvp++]) - 128; 147 | u = (0xff & yuv420sp[uvp++]) - 128; 148 | } 149 | int y1192 = 1192 * y; 150 | int r = (y1192 + 1634 * v); 151 | int g = (y1192 - 833 * v - 400 * u); 152 | int b = (y1192 + 2066 * u); 153 | if (r < 0) { 154 | r = 0; 155 | } else if (r > 262143) { 156 | r = 262143; 157 | } 158 | if (g < 0) { 159 | g = 0; 160 | } else if (g > 262143) { 161 | g = 262143; 162 | } 163 | if (b < 0) { 164 | b = 0; 165 | } else if (b > 262143) { 166 | b = 262143; 167 | } 168 | rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) 169 | | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff); 170 | } 171 | } 172 | return rgb; 173 | } 174 | 175 | } 176 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/util/CompareSizesByArea.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.util; 2 | 3 | import android.os.Build; 4 | import android.support.annotation.RequiresApi; 5 | import android.util.Size; 6 | 7 | import java.util.Comparator; 8 | 9 | /** 10 | * 比较 工具 11 | * 12 | * @packageName: cn.tongue.tonguecamera.util 13 | * @fileName: CompareSizesByArea 14 | * @date: 2019/4/16 13:42 15 | * @author: ymc 16 | * @QQ:745612618 17 | */ 18 | 19 | public class CompareSizesByArea implements Comparator { 20 | 21 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 22 | @Override 23 | public int compare(Size lhs, Size rhs) { 24 | // 在这里投射以确保乘法不会溢出 25 | return Long.signum((long) lhs.getWidth() * lhs.getHeight() - 26 | (long) rhs.getWidth() * rhs.getHeight()); 27 | } 28 | } -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/util/FilterEngine.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.util; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.opengl.GLES11Ext; 6 | import android.opengl.GLES20; 7 | 8 | import java.nio.ByteBuffer; 9 | import java.nio.ByteOrder; 10 | import java.nio.FloatBuffer; 11 | 12 | 13 | import camera.cn.cameramaster.R; 14 | 15 | import static android.opengl.GLES20.GL_FLOAT; 16 | import static android.opengl.GLES20.GL_FRAGMENT_SHADER; 17 | import static android.opengl.GLES20.GL_TRIANGLES; 18 | import static android.opengl.GLES20.GL_VERTEX_SHADER; 19 | import static android.opengl.GLES20.glActiveTexture; 20 | import static android.opengl.GLES20.glAttachShader; 21 | import static android.opengl.GLES20.glBindTexture; 22 | import static android.opengl.GLES20.glCompileShader; 23 | import static android.opengl.GLES20.glCreateProgram; 24 | import static android.opengl.GLES20.glCreateShader; 25 | import static android.opengl.GLES20.glDrawArrays; 26 | import static android.opengl.GLES20.glEnableVertexAttribArray; 27 | import static android.opengl.GLES20.glGetAttribLocation; 28 | import static android.opengl.GLES20.glGetError; 29 | import static android.opengl.GLES20.glGetUniformLocation; 30 | import static android.opengl.GLES20.glLinkProgram; 31 | import static android.opengl.GLES20.glShaderSource; 32 | import static android.opengl.GLES20.glUniform1i; 33 | import static android.opengl.GLES20.glUniformMatrix4fv; 34 | import static android.opengl.GLES20.glUseProgram; 35 | import static android.opengl.GLES20.glVertexAttribPointer; 36 | 37 | /** 38 | * 滤镜 工具 39 | * 参考url : [https://blog.csdn.net/lb377463323/article/details/78054892] 40 | * 41 | * @date 2019年2月12日 14:10:07 42 | * @author ymc 43 | */ 44 | 45 | public class FilterEngine { 46 | 47 | @SuppressLint("StaticFieldLeak") 48 | private static FilterEngine filterEngine = null; 49 | 50 | private Context mContext; 51 | /** 52 | * 存放顶点的Color数组 53 | */ 54 | private FloatBuffer mBuffer; 55 | private int mOESTextureId = -1; 56 | private int vertexShader = -1; 57 | private int fragmentShader = -1; 58 | 59 | private int mShaderProgram = -1; 60 | 61 | private int aPositionLocation = -1; 62 | private int aTextureCoordLocation = -1; 63 | private int uTextureMatrixLocation = -1; 64 | private int uTextureSamplerLocation = -1; 65 | /** 66 | * 每行前两个值为顶点坐标,后两个为纹理坐标 67 | */ 68 | private static final float[] VERTEX_DATA = { 69 | 1f, 1f, 1f, 1f, 70 | -1f, 1f, 0f, 1f, 71 | -1f, -1f, 0f, 0f, 72 | 1f, 1f, 1f, 1f, 73 | -1f, -1f, 0f, 0f, 74 | 1f, -1f, 1f, 0f 75 | }; 76 | 77 | public static final String POSITION_ATTRIBUTE = "aPosition"; 78 | public static final String TEXTURE_COORD_ATTRIBUTE = "aTextureCoordinate"; 79 | public static final String TEXTURE_MATRIX_UNIFORM = "uTextureMatrix"; 80 | public static final String TEXTURE_SAMPLER_UNIFORM = "uTextureSampler"; 81 | public static final String COLOR_TYPE = "vColorType"; 82 | 83 | /** 84 | * 构造方法 85 | * @param oestextureid oes id 86 | * @param context 上下文 87 | */ 88 | public FilterEngine(int oestextureid, Context context) { 89 | mContext = context; 90 | mOESTextureId = oestextureid; 91 | mBuffer = createBuffer(VERTEX_DATA); 92 | /** 93 | * 预览相机的着色器,顶点着色器不变,需要修改片元着色器,不再用sampler2D采样, 94 | * 需要使用samplerExternalOES 纹理采样器,并且要在头部增加使用扩展纹理的声明 95 | * #extension GL_OES_EGL_image_external : require。 96 | */ 97 | fragmentShader = loadShader(GL_FRAGMENT_SHADER, Utils.readShaderFromResource(mContext, R.raw.base_fragment_shader)); 98 | vertexShader = loadShader(GL_VERTEX_SHADER, Utils.readShaderFromResource(mContext, R.raw.base_vertex_shader)); 99 | mShaderProgram = linkProgram(vertexShader, fragmentShader); 100 | } 101 | 102 | /** 103 | * 创建 FloatBuffer 数组 (防止内存回收) 104 | * @param vertexData float 数组 105 | * @return FloatBuffer 106 | */ 107 | private FloatBuffer createBuffer(float[] vertexData) { 108 | FloatBuffer buffer = ByteBuffer.allocateDirect(vertexData.length * 4) 109 | .order(ByteOrder.nativeOrder()) 110 | .asFloatBuffer(); 111 | buffer.put(vertexData, 0, vertexData.length).position(0); 112 | return buffer; 113 | } 114 | 115 | /** 116 | * 加载着色器 117 | * GL_VERTEX_SHADER 代表生成顶点着色器 118 | * GL_FRAGMENT_SHADER 代表生成片段着色器 119 | * 120 | * @param type 类型 121 | * @param shaderSource shader string 122 | * @return shader 123 | */ 124 | private int loadShader(int type, String shaderSource) { 125 | int shader = glCreateShader(type); 126 | if (shader == 0) { 127 | throw new RuntimeException("Create Shader Failed!" + glGetError()); 128 | } 129 | glShaderSource(shader, shaderSource); 130 | glCompileShader(shader); 131 | return shader; 132 | } 133 | 134 | /** 135 | * 将两个Shader链接至program中 136 | * @param verShader verShader 137 | * @param fragShader fragShader 138 | * @return program 139 | */ 140 | private int linkProgram(int verShader, int fragShader) { 141 | int program = glCreateProgram(); 142 | if (program == 0) { 143 | throw new RuntimeException("Create Program Failed!" + glGetError()); 144 | } 145 | //附着顶点和片段着色器 146 | glAttachShader(program, verShader); 147 | glAttachShader(program, fragShader); 148 | // 绑定 program 149 | glLinkProgram(program); 150 | //告诉OpenGL ES使用此program 151 | glUseProgram(program); 152 | return program; 153 | } 154 | 155 | public void drawTexture(float[] transformMatrix) { 156 | aPositionLocation = glGetAttribLocation(mShaderProgram, FilterEngine.POSITION_ATTRIBUTE); 157 | aTextureCoordLocation = glGetAttribLocation(mShaderProgram, FilterEngine.TEXTURE_COORD_ATTRIBUTE); 158 | uTextureMatrixLocation = glGetUniformLocation(mShaderProgram, FilterEngine.TEXTURE_MATRIX_UNIFORM); 159 | uTextureSamplerLocation = glGetUniformLocation(mShaderProgram, FilterEngine.TEXTURE_SAMPLER_UNIFORM); 160 | 161 | glActiveTexture(GLES20.GL_TEXTURE0); 162 | glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mOESTextureId); 163 | glUniform1i(uTextureSamplerLocation, 0); 164 | glUniformMatrix4fv(uTextureMatrixLocation, 1, false, transformMatrix, 0); 165 | 166 | if (mBuffer != null) { 167 | mBuffer.position(0); 168 | glEnableVertexAttribArray(aPositionLocation); 169 | glVertexAttribPointer(aPositionLocation, 2, GL_FLOAT, false, 16, mBuffer); 170 | 171 | mBuffer.position(2); 172 | glEnableVertexAttribArray(aTextureCoordLocation); 173 | glVertexAttribPointer(aTextureCoordLocation, 2, GL_FLOAT, false, 16, mBuffer); 174 | 175 | glDrawArrays(GL_TRIANGLES, 0, 6); 176 | } 177 | } 178 | 179 | public int getShaderProgram() { 180 | return mShaderProgram; 181 | } 182 | 183 | public FloatBuffer getBuffer() { 184 | return mBuffer; 185 | } 186 | 187 | public int getOESTextureId() { 188 | return mOESTextureId; 189 | } 190 | 191 | public void setOESTextureId(int OESTextureId) { 192 | mOESTextureId = OESTextureId; 193 | } 194 | } 195 | 196 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/util/LabUtil.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.util; 2 | 3 | 4 | import java.util.Arrays; 5 | 6 | /** 7 | * rgb 转 lab 工具类 8 | * 9 | * @fileName: LabUtil 10 | * @date: 2019/4/3 13:38 11 | * @author: ymc 12 | * @QQ:745612618 13 | */ 14 | 15 | public class LabUtil { 16 | 17 | public static void main(String[] args) { 18 | for (int i = 0; i < 24; i++) { 19 | double[] a = AppConstant.rgbmap[i]; 20 | int fx = 0; 21 | int fx1 = -30; 22 | double rrr = a[0] + fx > 255 ? 255 :a[0] + fx; 23 | double ggg = a[1] + fx > 255 ? 255 :a[1] + fx; 24 | double bbb = a[2] + fx1 > 255 ? 255 :a[2] + fx1; 25 | double[] xyz = LabUtil.sRGB2XYZ(new double[]{rrr,ggg,bbb}); 26 | double[] lab = LabUtil.XYZ2Lab(xyz); 27 | double cha = Math.sqrt(Math.pow((lab[0] - AppConstant.labmap[i][0]), 2) 28 | + Math.pow((lab[1] - AppConstant.labmap[i][1]), 2) 29 | + Math.pow((lab[2] - AppConstant.labmap[i][2]), 2)); 30 | System.out.println(Arrays.toString(new double[]{rrr,ggg,bbb}) + " lab[]:"+ Arrays.toString(lab) + " 色差:"+cha); 31 | System.out.println("lab误差 l: "+(lab[0] - AppConstant.labmap[i][0]) + 32 | " a: "+(lab[1] - AppConstant.labmap[i][1])+" b: "+(lab[2] - AppConstant.labmap[i][2])); 33 | // Log.e("", a.toString() + " lab[]:"+lab.toString() + " 色差:"+cha); 34 | } 35 | } 36 | 37 | /** 38 | * D65 or D50 39 | */ 40 | private static boolean hasD50 = false; 41 | 42 | /** 43 | * lab 转 xyz 44 | * 45 | * @param Lab 46 | * @return 47 | */ 48 | public static double[] Lab2XYZ(double[] Lab) { 49 | double[] XYZ = new double[3]; 50 | double L, a, b; 51 | double fx, fy, fz; 52 | double Xn, Yn, Zn; 53 | // D50 54 | if (hasD50) { 55 | Xn = 96.42; 56 | Yn = 100; 57 | Zn = 82.51; 58 | } else { 59 | // D65 60 | Xn = 95.04; 61 | Yn = 100; 62 | Zn = 108.89; 63 | } 64 | L = Lab[0]; 65 | a = Lab[1]; 66 | b = Lab[2]; 67 | 68 | fy = (L + 16) / 116; 69 | fx = a / 500 + fy; 70 | fz = fy - b / 200; 71 | 72 | if (fx > 0.2069) { 73 | XYZ[0] = Xn * Math.pow(fx, 3); 74 | } else { 75 | XYZ[0] = Xn * (fx - 0.1379) * 0.1284; 76 | } 77 | 78 | if ((fy > 0.2069) || (L > 8)) { 79 | XYZ[1] = Yn * Math.pow(fy, 3); 80 | } else { 81 | XYZ[1] = Yn * (fy - 0.1379) * 0.1284; 82 | } 83 | 84 | if (fz > 0.2069) { 85 | XYZ[2] = Zn * Math.pow(fz, 3); 86 | } else { 87 | XYZ[2] = Zn * (fz - 0.1379) * 0.1284; 88 | } 89 | 90 | return XYZ; 91 | } 92 | 93 | /** 94 | * xyz 转为 lab 95 | * 96 | * @param XYZ 97 | * @return 98 | */ 99 | public static double[] XYZ2Lab(double[] XYZ) { 100 | double[] Lab = new double[3]; 101 | double X, Y, Z; 102 | X = XYZ[0]; 103 | Y = XYZ[1]; 104 | Z = XYZ[2]; 105 | double Xn, Yn, Zn; 106 | if (hasD50) { 107 | // D50 108 | Xn = 96.42; 109 | Yn = 100; 110 | Zn = 82.51; 111 | } else { 112 | // D65 113 | Xn = 95.04; 114 | Yn = 100; 115 | Zn = 108.89; 116 | } 117 | double XXn, YYn, ZZn; 118 | XXn = X / Xn; 119 | YYn = Y / Yn; 120 | ZZn = Z / Zn; 121 | 122 | double fx, fy, fz; 123 | if (XXn > 0.008856) { 124 | fx = Math.pow(XXn, 0.333333); 125 | } else { 126 | fx = 7.787 * XXn + 0.137931; 127 | } 128 | if (YYn > 0.008856) { 129 | fy = Math.pow(YYn, 0.333333); 130 | } else { 131 | fy = 7.787 * YYn + 0.137931; 132 | } 133 | if (ZZn > 0.008856) { 134 | fz = Math.pow(ZZn, 0.333333); 135 | } else { 136 | fz = 7.787 * ZZn + 0.137931; 137 | } 138 | Lab[0] = 116 * fy - 16; 139 | Lab[1] = 500 * (fx - fy); 140 | Lab[2] = 200 * (fy - fz); 141 | 142 | return Lab; 143 | } 144 | 145 | /** 146 | * rgb 转 xyz 147 | * 148 | * @return double[] 149 | */ 150 | public static double[] sRGB2XYZ(double[] RGB) { 151 | double[] XYZ = new double[3]; 152 | double sR, sG, sB; 153 | sR = RGB[0]; 154 | sG = RGB[1]; 155 | sB = RGB[2]; 156 | sR /= 255; 157 | sG /= 255; 158 | sB /= 255; 159 | 160 | if (sR <= 0.04045) { 161 | sR = sR / 12.92; 162 | } else { 163 | sR = Math.pow(((sR + 0.055) / 1.055), 2.4); 164 | } 165 | 166 | if (sG <= 0.04045) { 167 | sG = sG / 12.92; 168 | } else { 169 | sG = Math.pow(((sG + 0.055) / 1.055), 2.4); 170 | } 171 | 172 | if (sB <= 0.04045) { 173 | sB = sB / 12.92; 174 | } else { 175 | sB = Math.pow(((sB + 0.055) / 1.055), 2.4); 176 | } 177 | if (hasD50) { 178 | // D50 179 | XYZ[0] = 43.6052025 * sR + 38.5081593 * sG + 14.3087414 * sB; 180 | XYZ[1] = 22.2491598 * sR + 71.6886060 * sG + 6.0621486 * sB; 181 | XYZ[2] = 1.3929122 * sR + 9.7097002 * sG + 71.4185470 * sB; 182 | } else { 183 | // D65 184 | XYZ[0] = 41.24 * sR + 35.76 * sG + 18.05 * sB; 185 | XYZ[1] = 21.26 * sR + 71.52 * sG + 7.22 * sB; 186 | XYZ[2] = 1.93 * sR + 11.92 * sG + 95.05 * sB; 187 | } 188 | return XYZ; 189 | } 190 | 191 | /** 192 | * xyz 转 rgb 193 | * 194 | * @param XYZ double[] 195 | * @return double[] 196 | */ 197 | public static double[] XYZ2sRGB(double[] XYZ) { 198 | double[] sRGB = new double[3]; 199 | double X, Y, Z; 200 | double dr = 0, dg = 0, db = 0; 201 | X = XYZ[0]; 202 | Y = XYZ[1]; 203 | Z = XYZ[2]; 204 | 205 | if (hasD50) { 206 | // TODO: 2019/4/3 D50格式暂时没有找到 D50格式 207 | } else { 208 | dr = 0.032406 * X - 0.015371 * Y - 0.0049895 * Z; 209 | dg = -0.0096891 * X + 0.018757 * Y + 0.00041914 * Z; 210 | db = 0.00055708 * X - 0.0020401 * Y + 0.01057 * Z; 211 | } 212 | 213 | if (dr <= 0.00313) { 214 | dr = dr * 12.92; 215 | } else { 216 | dr = Math.exp(Math.log(dr) / 2.4) * 1.055 - 0.055; 217 | } 218 | 219 | if (dg <= 0.00313) { 220 | dg = dg * 12.92; 221 | } else { 222 | dg = Math.exp(Math.log(dg) / 2.4) * 1.055 - 0.055; 223 | } 224 | 225 | if (db <= 0.00313) { 226 | db = db * 12.92; 227 | } else { 228 | db = Math.exp(Math.log(db) / 2.4) * 1.055 - 0.055; 229 | } 230 | 231 | dr = dr * 255; 232 | dg = dg * 255; 233 | db = db * 255; 234 | 235 | dr = Math.min(255, dr); 236 | dg = Math.min(255, dg); 237 | db = Math.min(255, db); 238 | 239 | sRGB[0] = dr + 0.5; 240 | sRGB[1] = dg + 0.5; 241 | sRGB[2] = db + 0.5; 242 | 243 | return sRGB; 244 | } 245 | 246 | } 247 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/util/MatrixUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * FastDrawerHelper.java 4 | * 5 | * Created by Wuwang on 2016/11/17 6 | * Copyright © 2016年 深圳哎吖科技. All rights reserved. 7 | */ 8 | package camera.cn.cameramaster.util; 9 | 10 | import android.opengl.Matrix; 11 | 12 | /** 13 | * 矩阵 工具类 14 | */ 15 | public enum MatrixUtils { 16 | ; 17 | public static final int TYPE_FITXY=0; 18 | public static final int TYPE_CENTERCROP=1; 19 | public static final int TYPE_CENTERINSIDE=2; 20 | public static final int TYPE_FITSTART=3; 21 | public static final int TYPE_FITEND=4; 22 | 23 | MatrixUtils(){ 24 | 25 | } 26 | 27 | /** 28 | * use {@link #getMatrix} instead 29 | */ 30 | @Deprecated 31 | public static void getShowMatrix(float[] matrix,int imgWidth,int imgHeight,int viewWidth,int 32 | viewHeight){ 33 | if(imgHeight>0&&imgWidth>0&&viewWidth>0&&viewHeight>0){ 34 | float sWhView=(float)viewWidth/viewHeight; 35 | float sWhImg=(float)imgWidth/imgHeight; 36 | float[] projection=new float[16]; 37 | float[] camera=new float[16]; 38 | if(sWhImg>sWhView){ 39 | Matrix.orthoM(projection,0,-sWhView/sWhImg,sWhView/sWhImg,-1,1,1,3); 40 | }else{ 41 | Matrix.orthoM(projection,0,-1,1,-sWhImg/sWhView,sWhImg/sWhView,1,3); 42 | } 43 | Matrix.setLookAtM(camera,0,0,0,1,0,0,0,0,1,0); 44 | Matrix.multiplyMM(matrix,0,projection,0,camera,0); 45 | } 46 | } 47 | 48 | public static void getMatrix(float[] matrix,int type,int imgWidth,int imgHeight,int viewWidth, 49 | int viewHeight){ 50 | if(imgHeight>0&&imgWidth>0&&viewWidth>0&&viewHeight>0){ 51 | float[] projection=new float[16]; 52 | float[] camera=new float[16]; 53 | if(type==TYPE_FITXY){ 54 | Matrix.orthoM(projection,0,-1,1,-1,1,1,3); 55 | Matrix.setLookAtM(camera,0,0,0,1,0,0,0,0,1,0); 56 | Matrix.multiplyMM(matrix,0,projection,0,camera,0); 57 | } 58 | float sWhView=(float)viewWidth/viewHeight; 59 | float sWhImg=(float)imgWidth/imgHeight; 60 | if(sWhImg>sWhView){ 61 | switch (type){ 62 | case TYPE_CENTERCROP: 63 | Matrix.orthoM(projection,0,-sWhView/sWhImg,sWhView/sWhImg,-1,1,1,3); 64 | break; 65 | case TYPE_CENTERINSIDE: 66 | Matrix.orthoM(projection,0,-1,1,-sWhImg/sWhView,sWhImg/sWhView,1,3); 67 | break; 68 | case TYPE_FITSTART: 69 | Matrix.orthoM(projection,0,-1,1,1-2*sWhImg/sWhView,1,1,3); 70 | break; 71 | case TYPE_FITEND: 72 | Matrix.orthoM(projection,0,-1,1,-1,2*sWhImg/sWhView-1,1,3); 73 | break; 74 | } 75 | }else{ 76 | switch (type){ 77 | case TYPE_CENTERCROP: 78 | Matrix.orthoM(projection,0,-1,1,-sWhImg/sWhView,sWhImg/sWhView,1,3); 79 | break; 80 | case TYPE_CENTERINSIDE: 81 | Matrix.orthoM(projection,0,-sWhView/sWhImg,sWhView/sWhImg,-1,1,1,3); 82 | break; 83 | case TYPE_FITSTART: 84 | Matrix.orthoM(projection,0,-1,2*sWhView/sWhImg-1,-1,1,1,3); 85 | break; 86 | case TYPE_FITEND: 87 | Matrix.orthoM(projection,0,1-2*sWhView/sWhImg,1,-1,1,1,3); 88 | break; 89 | } 90 | } 91 | Matrix.setLookAtM(camera,0,0,0,1,0,0,0,0,1,0); 92 | Matrix.multiplyMM(matrix,0,projection,0,camera,0); 93 | } 94 | } 95 | 96 | public static void getCenterInsideMatrix(float[] matrix,int imgWidth,int imgHeight,int viewWidth,int 97 | viewHeight){ 98 | if(imgHeight>0&&imgWidth>0&&viewWidth>0&&viewHeight>0){ 99 | float sWhView=(float)viewWidth/viewHeight; 100 | float sWhImg=(float)imgWidth/imgHeight; 101 | float[] projection=new float[16]; 102 | float[] camera=new float[16]; 103 | if(sWhImg>sWhView){ 104 | Matrix.orthoM(projection,0,-1,1,-sWhImg/sWhView,sWhImg/sWhView,1,3); 105 | }else{ 106 | Matrix.orthoM(projection,0,-sWhView/sWhImg,sWhView/sWhImg,-1,1,1,3); 107 | } 108 | Matrix.setLookAtM(camera,0,0,0,1,0,0,0,0,1,0); 109 | Matrix.multiplyMM(matrix,0,projection,0,camera,0); 110 | } 111 | } 112 | 113 | public static float[] rotate(float[] m,float angle){ 114 | Matrix.rotateM(m,0,angle,0,0,1); 115 | return m; 116 | } 117 | 118 | public static float[] flip(float[] m,boolean x,boolean y){ 119 | if(x||y){ 120 | Matrix.scaleM(m,0,x?-1:1,y?-1:1,1); 121 | } 122 | return m; 123 | } 124 | 125 | public static float[] scale(float[] m,float x,float y){ 126 | Matrix.scaleM(m,0,x,y,1); 127 | return m; 128 | } 129 | 130 | public static float[] getOriginalMatrix(){ 131 | return new float[]{ 132 | 1,0,0,0, 133 | 0,1,0,0, 134 | 0,0,1,0, 135 | 0,0,0,1 136 | }; 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/util/Utils.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.util; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES11Ext; 5 | import android.opengl.GLES20; 6 | import android.os.Environment; 7 | import android.util.Log; 8 | 9 | import java.io.BufferedReader; 10 | import java.io.File; 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | import java.io.InputStreamReader; 14 | import java.text.SimpleDateFormat; 15 | import java.util.Date; 16 | 17 | import javax.microedition.khronos.opengles.GL10; 18 | 19 | import static android.provider.MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE; 20 | import static android.provider.MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO; 21 | 22 | /** 23 | * opengles utils 24 | * 25 | * @date 2019年2月12日 14:03:59 26 | * @author ymc 27 | */ 28 | 29 | public class Utils { 30 | 31 | private static final String TAG = "Utils"; 32 | 33 | /** 34 | * 创建 oes id 35 | * @return oesId 36 | */ 37 | public static int createOESTextureObject() { 38 | int[] tex = new int[1]; 39 | //生成一个纹理 40 | GLES20.glGenTextures(1, tex, 0); 41 | //将此纹理绑定到外部纹理上 42 | GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, tex[0]); 43 | //设置纹理过滤参数 44 | GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 45 | GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST); 46 | GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 47 | GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); 48 | GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 49 | GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE); 50 | GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 51 | GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE); 52 | //解除纹理绑定 53 | GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0); 54 | return tex[0]; 55 | } 56 | 57 | public static String readShaderFromResource(Context context, int resourceId) { 58 | StringBuilder builder = new StringBuilder(); 59 | InputStream is = null; 60 | InputStreamReader isr = null; 61 | BufferedReader br = null; 62 | try { 63 | is = context.getResources().openRawResource(resourceId); 64 | isr = new InputStreamReader(is); 65 | br = new BufferedReader(isr); 66 | String line; 67 | while ((line = br.readLine()) != null) { 68 | builder.append(line).append("\n"); 69 | } 70 | } catch (IOException e) { 71 | e.printStackTrace(); 72 | } finally { 73 | try { 74 | if (is != null) { 75 | is.close(); 76 | is = null; 77 | } 78 | if (isr != null) { 79 | isr.close(); 80 | isr = null; 81 | } 82 | if (br != null) { 83 | br.close(); 84 | br = null; 85 | } 86 | } catch (IOException e) { 87 | e.printStackTrace(); 88 | } 89 | } 90 | return builder.toString(); 91 | } 92 | 93 | 94 | /** 95 | * 获取输出照片视频路径 96 | * @param mContext 上下文 97 | * @param mediaType 拍照视频类型 98 | * @return 文件地址 99 | */ 100 | public static File getOutputMediaFile(Context mContext, int mediaType) { 101 | String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); 102 | String fileName = null; 103 | File storageDir = null; 104 | if (mediaType == MEDIA_TYPE_IMAGE) { 105 | fileName = "JPEG_" + timeStamp + "_"; 106 | storageDir = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES); 107 | } else if (mediaType == MEDIA_TYPE_VIDEO) { 108 | fileName = "MP4_" + timeStamp + "_"; 109 | storageDir = mContext.getExternalFilesDir(Environment.DIRECTORY_MOVIES); 110 | } 111 | 112 | // Create the storage directory if it does not exist 113 | if (!storageDir.exists()) { 114 | if (!storageDir.mkdirs()) { 115 | Log.d(TAG, "failed to create directory"); 116 | return null; 117 | } 118 | } 119 | 120 | File file = null; 121 | try { 122 | file = File.createTempFile( 123 | fileName, /* prefix */ 124 | (mediaType == MEDIA_TYPE_IMAGE) ? ".jpg" : ".mp4", /* suffix */ 125 | storageDir /* directory */ 126 | ); 127 | Log.d(TAG, "getOutputMediaFile: absolutePath==" + file.getAbsolutePath()); 128 | } catch (IOException e) { 129 | e.printStackTrace(); 130 | } 131 | return file; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/util/cameravideo/CoordinateTransformer.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.util.cameravideo; 2 | 3 | import android.graphics.Matrix; 4 | import android.graphics.Rect; 5 | import android.graphics.RectF; 6 | import android.hardware.camera2.CameraCharacteristics; 7 | import android.os.Build; 8 | import android.support.annotation.RequiresApi; 9 | 10 | /** 11 | * 将坐标转换为预览坐标空间和相机驱动程序坐标空间。 12 | * @author ymc 13 | */ 14 | 15 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 16 | public class CoordinateTransformer { 17 | 18 | private final Matrix mPreviewToCameraTransform; 19 | private RectF mDriverRectF; 20 | 21 | /** 22 | * 将矩形转换为相机坐标或从相机坐标转换并预览坐标空间。 23 | * @param chr camera characteristics 24 | * @param previewRect the preview rectangle size and position. 25 | */ 26 | 27 | public CoordinateTransformer(CameraCharacteristics chr, RectF previewRect) { 28 | if (!hasNonZeroArea(previewRect)) { 29 | throw new IllegalArgumentException("previewRect"); 30 | } 31 | Rect rect = chr.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 32 | Integer sensorOrientation = chr.get(CameraCharacteristics.SENSOR_ORIENTATION); 33 | int rotation = sensorOrientation == null ? 90 : sensorOrientation; 34 | mDriverRectF = new RectF(rect); 35 | Integer face = chr.get(CameraCharacteristics.LENS_FACING); 36 | boolean mirrorX = face != null && face == CameraCharacteristics.LENS_FACING_FRONT; 37 | mPreviewToCameraTransform = previewToCameraTransform(mirrorX, rotation, previewRect); 38 | } 39 | 40 | /** 41 | * 将预览视图空间中的矩形转换为新的矩形相机视图空间。 42 | * 43 | * @param source the rectangle in preview view space 44 | * @return the rectangle in camera view space. 45 | */ 46 | public RectF toCameraSpace(RectF source) { 47 | RectF result = new RectF(); 48 | mPreviewToCameraTransform.mapRect(result, source); 49 | return result; 50 | } 51 | 52 | private Matrix previewToCameraTransform(boolean mirrorX, int sensorOrientation, 53 | RectF previewRect) { 54 | Matrix transform = new Matrix(); 55 | // Need mirror for front camera. 56 | transform.setScale(mirrorX ? -1 : 1, 1); 57 | // Because preview orientation is different form sensor orientation, 58 | // rotate to same orientation, Counterclockwise. 59 | transform.postRotate(-sensorOrientation); 60 | // Map rotated matrix to preview rect 61 | transform.mapRect(previewRect); 62 | // Map preview coordinates to driver coordinates 63 | Matrix fill = new Matrix(); 64 | fill.setRectToRect(previewRect, mDriverRectF, Matrix.ScaleToFit.FILL); 65 | // Concat the previous transform on top of the fill behavior. 66 | transform.setConcat(fill, transform); 67 | // finally get transform matrix 68 | return transform; 69 | } 70 | 71 | private boolean hasNonZeroArea(RectF rect) { 72 | return rect.width() != 0 && rect.height() != 0; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/util/cameravideo/ICamera2.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.util.cameravideo; 2 | 3 | import android.util.Size; 4 | import android.view.Surface; 5 | import android.view.TextureView; 6 | 7 | import java.io.File; 8 | 9 | /** 10 | * 相机 接口类 11 | */ 12 | 13 | public interface ICamera2 { 14 | 15 | /** 16 | * 缩放 17 | * @param zoom 缩放比例 18 | */ 19 | void cameraZoom(float zoom); 20 | 21 | /** 22 | * 打开摄像头 23 | */ 24 | boolean openCamera(CameraType cameraType); 25 | 26 | /** 27 | * 关闭摄像头 28 | */ 29 | void closeCamera(); 30 | 31 | /** 32 | * 切换摄像头 33 | * @param cameraType 切换摄像头类型 34 | * @return boolean 是否切换成功 35 | */ 36 | boolean switchCamera(CameraType cameraType); 37 | 38 | /** 39 | * 开启相机的预览模式 40 | */ 41 | boolean startPreview(); 42 | 43 | /** 44 | * 停止预览 45 | */ 46 | void resumePreview(); 47 | 48 | /** 49 | * 开始视频的录制 50 | * @param path 存储路径 51 | * @param mediaType 文件类型 52 | */ 53 | boolean startVideoRecord(String path, int mediaType); 54 | 55 | /** 56 | * 停止视频录制 57 | */ 58 | void stopVideoRecord(); 59 | 60 | /** 61 | * 拍照 62 | * @param path 存储路径 63 | * @param mediaType 文件类型 64 | */ 65 | boolean takePhone(String path, MediaType mediaType); 66 | 67 | /** 68 | * 获取预览大小 69 | * @return 70 | */ 71 | Size getPreViewSize(); 72 | 73 | void setSurface(Surface surface); 74 | 75 | void setTextureView(TextureView textureView); 76 | 77 | void setTakePhotoListener(TakePhotoListener mTakePhotoListener); 78 | 79 | void setCameraReady(CameraReady mCameraReady); 80 | 81 | void flashSwitchState(FlashState mFlashState); 82 | 83 | void setCameraState(CameraMode cameraMode); 84 | 85 | /** 86 | * 手动请求对焦 87 | * @param x 88 | * @param y 89 | */ 90 | void requestFocus(float x, float y); 91 | 92 | /** 93 | * 摄像头模式类型 94 | */ 95 | enum CameraMode 96 | { 97 | RECORD_VIDEO, 98 | TAKE_PHOTO 99 | } 100 | 101 | /** 102 | * 当前只有mp4类型 103 | */ 104 | enum MediaType 105 | { 106 | MP4, 107 | JPEG, 108 | } 109 | 110 | /** 111 | * 摄像头类型 112 | */ 113 | enum CameraType 114 | { 115 | FRONT, 116 | BACK, 117 | USB 118 | } 119 | 120 | /** 121 | * 灯光状态 122 | */ 123 | enum FlashState 124 | { 125 | CLOSE, 126 | AUTO, 127 | OPEN 128 | } 129 | 130 | interface TakePhotoListener{ 131 | void onTakePhotoFinish(File file, int photoRotation, int width, int height); 132 | } 133 | 134 | interface CameraReady 135 | { 136 | void onCameraReady(); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/util/cameravideo/IVideoControl.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.util.cameravideo; 2 | 3 | /** 4 | * 视频接口 5 | */ 6 | 7 | public interface IVideoControl { 8 | 9 | /** 10 | * 播放视频 11 | */ 12 | void play(); 13 | 14 | /** 15 | * 暂停视频播放 16 | */ 17 | void pause(); 18 | 19 | /** 20 | * 继续播放视频,前提是暂停了视频 21 | */ 22 | void resume(); 23 | 24 | /** 25 | * 停止播放视频 26 | */ 27 | void stop(); 28 | 29 | /** 30 | * 进度条快进 31 | * @param timeStamp 32 | */ 33 | void seekTo(int timeStamp); 34 | 35 | void setPlaySeekTimeListener(PlaySeekTimeListener mPlaySeekTimeListener); 36 | 37 | void setPlayStateListener(PlayStateListener mPlayStateListener); 38 | 39 | interface PlaySeekTimeListener 40 | { 41 | void onSeekTime(int allTime, int time); 42 | } 43 | 44 | /** 45 | * 播放状态 46 | */ 47 | interface PlayStateListener{ 48 | 49 | void onStartListener(int width, int height); 50 | 51 | void onCompletionListener(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/view/AnimationTextView.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.view; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.os.Build; 6 | import android.os.Handler; 7 | import android.support.annotation.RequiresApi; 8 | import android.util.AttributeSet; 9 | import android.view.animation.Animation; 10 | import android.widget.TextView; 11 | 12 | /** 13 | * 文字显示 一秒后消失 14 | */ 15 | 16 | @SuppressLint("AppCompatCustomView") 17 | public class AnimationTextView extends TextView { 18 | private Handler mMainHandler; 19 | private Animation mAnimation; 20 | /** 21 | * 防止又换了个text,但是上次哪个还没有消失即将小时就把新的text的给消失了 22 | */ 23 | public int mTimes = 0; 24 | 25 | public AnimationTextView(Context context) { 26 | super(context); 27 | } 28 | 29 | public AnimationTextView(Context context, AttributeSet attrs) { 30 | super(context, attrs); 31 | } 32 | 33 | public AnimationTextView(Context context, AttributeSet attrs, int defStyleAttr) { 34 | super(context, attrs, defStyleAttr); 35 | } 36 | 37 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 38 | public AnimationTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 39 | super(context, attrs, defStyleAttr, defStyleRes); 40 | } 41 | 42 | public void setmMainHandler(Handler mMainHandler) { 43 | this.mMainHandler = mMainHandler; 44 | } 45 | 46 | public void setmAnimation(Animation mAnimation) { 47 | this.mAnimation = mAnimation; 48 | } 49 | 50 | public void start(String text, int message) { 51 | if (mAnimation == null || mMainHandler == null) { 52 | return; 53 | } 54 | this.setVisibility(VISIBLE); 55 | mTimes++; 56 | this.setText(text); 57 | this.startAnimation(mAnimation); 58 | new Thread(new SleepThread(mMainHandler, message, 1000, Integer.valueOf(mTimes))).start(); 59 | } 60 | 61 | public void stop() { 62 | this.setVisibility(GONE); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/view/AutoFitTextureView.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.view; 2 | 3 | import android.content.Context; 4 | import android.graphics.Matrix; 5 | import android.util.AttributeSet; 6 | import android.view.TextureView; 7 | 8 | /** 9 | * 自定义 TextureView 10 | * 重新计算预览宽高 11 | * 12 | * @fileName: AutoFitTextureView 13 | * @date: 2019/1/28 17:00 14 | * @author: ymc 15 | * @QQ:745612618 16 | */ 17 | 18 | public class AutoFitTextureView extends TextureView { 19 | 20 | private int mRatioWidth = 0; 21 | private int mRatioHeight = 0; 22 | 23 | public AutoFitTextureView(Context context) { 24 | this(context, null); 25 | } 26 | 27 | public AutoFitTextureView(Context context, AttributeSet attrs) { 28 | this(context, attrs, 0); 29 | } 30 | 31 | public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) { 32 | super(context, attrs, defStyle); 33 | } 34 | 35 | /** 36 | * 设置此视图的纵横比。将根据比率测量视图的大小 根据参数计算。注意,参数的实际大小无关紧要 37 | * 调用setAspectRatio(2,3)和setAspectRatio(4,6)会产生相同的结果。 38 | * 39 | * @param width Relative horizontal size 40 | * @param height Relative vertical size 41 | */ 42 | public void setAspectRatio(int width, int height) { 43 | if (width < 0 || height < 0) { 44 | throw new IllegalArgumentException("Size cannot be negative."); 45 | } 46 | mRatioWidth = width; 47 | mRatioHeight = height; 48 | 49 | float mRatio = (float) mRatioWidth / (float) mRatioHeight; //算出相机的缩放比例 50 | 51 | float w = mRatio * getHeight(); 52 | float scale; 53 | if (w > getWidth()) 54 | scale = w / (float) getWidth(); 55 | else 56 | scale = (float) getWidth() / w; 57 | 58 | Matrix matrix = new Matrix(); 59 | matrix.postScale(scale, 1, getWidth() / 2, getHeight() / 2); 60 | setTransform(matrix); 61 | } 62 | 63 | /** 64 | * 视频宽度适配 65 | * @param width 66 | * @param height 67 | */ 68 | public void setVideoAspectRatio(int width, int height) 69 | { 70 | if (width < 0 || height < 0) { 71 | throw new IllegalArgumentException("Size cannot be negative."); 72 | } 73 | mRatioWidth = width; 74 | mRatioHeight = height; 75 | 76 | float mRatio = (float) mRatioWidth / (float) mRatioHeight; //算出相机的缩放比例 77 | if(mRatio < 1.0) 78 | { 79 | setAspectRatio(width, height); 80 | }else { 81 | float h = getWidth() / mRatio; 82 | float scale; 83 | if (h > getHeight()) 84 | scale = (float) getHeight() / h; 85 | else 86 | scale = h / (float) getHeight(); 87 | 88 | Matrix matrix = new Matrix(); 89 | matrix.postScale(1, scale, getWidth() / 2, getHeight() / 2); 90 | setTransform(matrix); 91 | } 92 | } 93 | 94 | } -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/view/AutoTextureView.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.view; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.TextureView; 6 | 7 | /** 8 | * 自定义 正方形预览界面 9 | * 10 | * @packageName: camera.cn.cameramaster.view 11 | * @fileName: AutoTextureView 12 | * @date: 2019/5/9 16:15 13 | * @author: ymc 14 | * @QQ:745612618 15 | */ 16 | 17 | public class AutoTextureView extends TextureView { 18 | 19 | private int mRatioWidth = 0; 20 | private int mRatioHeight = 0; 21 | 22 | public AutoTextureView(Context context) { 23 | super(context); 24 | } 25 | 26 | public AutoTextureView(Context context, AttributeSet attrs) { 27 | super(context, attrs); 28 | } 29 | 30 | public AutoTextureView(Context context, AttributeSet attrs, int defStyleAttr) { 31 | super(context, attrs, defStyleAttr); 32 | } 33 | /** 34 | * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio 35 | * calculated from the parameters. Note that the actual sizes of parameters don't matter, that 36 | * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result. 37 | * 38 | * @param width Relative horizontal size 39 | * @param height Relative vertical size 40 | */ 41 | public void setAspectRatio(int width, int height) { 42 | if (width < 0 || height < 0) { 43 | throw new IllegalArgumentException("Size cannot be negative."); 44 | } 45 | mRatioWidth = width; 46 | mRatioHeight = height; 47 | requestLayout(); 48 | } 49 | 50 | @Override 51 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 52 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 53 | int width = MeasureSpec.getSize(widthMeasureSpec); 54 | int height = MeasureSpec.getSize(heightMeasureSpec); 55 | if (0 == mRatioWidth || 0 == mRatioHeight) { 56 | setMeasuredDimension(width, height); 57 | } else { 58 | if (width < height * mRatioWidth / mRatioHeight) { 59 | setMeasuredDimension(width, width * mRatioHeight / mRatioWidth); 60 | } else { 61 | setMeasuredDimension(height * mRatioWidth / mRatioHeight, height); 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/view/AwbSeekBar.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.view; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.os.Build; 6 | import android.support.annotation.RequiresApi; 7 | import android.util.AttributeSet; 8 | import android.widget.SeekBar; 9 | 10 | /** 11 | * 自定义 8种白平衡状态 选择 seekBar 12 | * 13 | * @author ymc 14 | */ 15 | 16 | @SuppressLint("AppCompatCustomView") 17 | public class AwbSeekBar extends SeekBar { 18 | 19 | private int mProgress; 20 | private AwbSeekBar mAwbSeekBar = this; 21 | private OnAwbSeekBarChangeListener mOnAwbSeekBarChangeListener; 22 | 23 | public AwbSeekBar(Context context) { 24 | super(context); 25 | init(); 26 | } 27 | 28 | public AwbSeekBar(Context context, AttributeSet attrs) { 29 | super(context, attrs); 30 | init(); 31 | } 32 | 33 | public AwbSeekBar(Context context, AttributeSet attrs, int defStyleAttr) { 34 | super(context, attrs, defStyleAttr); 35 | init(); 36 | } 37 | 38 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 39 | public AwbSeekBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 40 | super(context, attrs, defStyleAttr, defStyleRes); 41 | init(); 42 | } 43 | public void setmOnAwbSeekBarChangeListener(OnAwbSeekBarChangeListener mOnAwbSeekBarChangeListener) { 44 | this.mOnAwbSeekBarChangeListener = mOnAwbSeekBarChangeListener; 45 | } 46 | 47 | private void init() { 48 | this.setMax(70); 49 | this.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { 50 | @Override 51 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 52 | mProgress = progress; 53 | if (mOnAwbSeekBarChangeListener != null) { 54 | if (0 <= mProgress && mProgress < 5) { 55 | mOnAwbSeekBarChangeListener.doInProgress1(); 56 | } else if (5 <= mProgress && mProgress < 15) { 57 | mOnAwbSeekBarChangeListener.doInProgress2(); 58 | } else if (15 <= mProgress && mProgress < 25) { 59 | mOnAwbSeekBarChangeListener.doInProgress3(); 60 | } else if (25 <= mProgress && mProgress < 35) { 61 | mOnAwbSeekBarChangeListener.doInProgress4(); 62 | } else if (35 <= mProgress && mProgress < 45) { 63 | mOnAwbSeekBarChangeListener.doInProgress5(); 64 | } else if (45 <= mProgress && mProgress < 55) { 65 | mOnAwbSeekBarChangeListener.doInProgress6(); 66 | } else if (55 <= mProgress && mProgress < 65) { 67 | mOnAwbSeekBarChangeListener.doInProgress7(); 68 | } else if (65 <= mProgress && mProgress < 70) { 69 | mOnAwbSeekBarChangeListener.doInProgress8(); 70 | } 71 | } 72 | } 73 | 74 | @Override 75 | public void onStartTrackingTouch(SeekBar seekBar) { 76 | mOnAwbSeekBarChangeListener.onStartTrackingTouch(seekBar); 77 | } 78 | 79 | @Override 80 | public void onStopTrackingTouch(SeekBar seekBar) { 81 | int num = 0; 82 | if (0 <= mProgress && mProgress < 5) { 83 | mAwbSeekBar.setProgress(0); 84 | num = 0; 85 | } else if (5 <= mProgress && mProgress < 15) { 86 | mAwbSeekBar.setProgress(10); 87 | num = 10; 88 | } else if (15 <= mProgress && mProgress < 25) { 89 | mAwbSeekBar.setProgress(20); 90 | num = 20; 91 | } else if (25 <= mProgress && mProgress < 35) { 92 | mAwbSeekBar.setProgress(30); 93 | num = 30; 94 | } else if (35 <= mProgress && mProgress < 45) { 95 | mAwbSeekBar.setProgress(40); 96 | num = 40; 97 | } else if (45 <= mProgress && mProgress < 55) { 98 | mAwbSeekBar.setProgress(50); 99 | num = 50; 100 | } else if (55 <= mProgress && mProgress < 65) { 101 | mAwbSeekBar.setProgress(60); 102 | num = 60; 103 | } else if (65 <= mProgress && mProgress < 70) { 104 | mAwbSeekBar.setProgress(70); 105 | num = 70; 106 | } 107 | if (mOnAwbSeekBarChangeListener != null) { 108 | mOnAwbSeekBarChangeListener.onStopTrackingTouch(num); 109 | } 110 | } 111 | }); 112 | } 113 | 114 | public interface OnAwbSeekBarChangeListener { 115 | public abstract void doInProgress1(); 116 | 117 | public abstract void doInProgress2(); 118 | 119 | public abstract void doInProgress3(); 120 | 121 | public abstract void doInProgress4(); 122 | 123 | public abstract void doInProgress5(); 124 | 125 | public abstract void doInProgress6(); 126 | 127 | public abstract void doInProgress7(); 128 | 129 | public abstract void doInProgress8(); 130 | 131 | public abstract void onStopTrackingTouch(int num); 132 | 133 | public abstract void onStartTrackingTouch(SeekBar seekBar); 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/view/AwbSeekBarChangeListener.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.view; 2 | 3 | import android.content.Context; 4 | import android.hardware.camera2.CameraAccessException; 5 | import android.hardware.camera2.CameraCaptureSession; 6 | import android.hardware.camera2.CameraMetadata; 7 | import android.hardware.camera2.CaptureRequest; 8 | import android.os.Build; 9 | import android.os.Handler; 10 | import android.support.annotation.RequiresApi; 11 | import android.util.Log; 12 | import android.view.View; 13 | import android.view.animation.Animation; 14 | import android.view.animation.AnimationUtils; 15 | import android.widget.SeekBar; 16 | import android.widget.TextView; 17 | 18 | import camera.cn.cameramaster.R; 19 | import camera.cn.cameramaster.view.AwbSeekBar; 20 | 21 | 22 | /** 23 | * 自定义 seekbar 滑动监听事件 24 | * @author ymc 25 | */ 26 | 27 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 28 | public class AwbSeekBarChangeListener implements AwbSeekBar.OnAwbSeekBarChangeListener { 29 | private TextView mTextView; 30 | private CaptureRequest.Builder mPreviewBuilder; 31 | private CameraCaptureSession mCameraCaptureSession; 32 | private Handler mHandler; 33 | private CameraCaptureSession.CaptureCallback mPreviewSessionCallback; 34 | 35 | private Animation mAlphaInAnimation; 36 | private Animation mAlphaOutAnimation; 37 | 38 | public AwbSeekBarChangeListener(Context mContext, TextView mTextView, CaptureRequest.Builder mPreviewBuilder, 39 | CameraCaptureSession mCameraCaptureSession, Handler mHandler, 40 | CameraCaptureSession.CaptureCallback mPreviewSessionCallback) { 41 | this.mTextView = mTextView; 42 | this.mPreviewBuilder = mPreviewBuilder; 43 | this.mCameraCaptureSession = mCameraCaptureSession; 44 | this.mHandler = mHandler; 45 | this.mPreviewSessionCallback = mPreviewSessionCallback; 46 | mAlphaInAnimation = AnimationUtils.loadAnimation(mContext, R.anim.alpha_in); 47 | mAlphaOutAnimation = AnimationUtils.loadAnimation(mContext, R.anim.alpha_out); 48 | } 49 | 50 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 51 | @Override 52 | public void doInProgress1() { 53 | mTextView.setText("自动"); 54 | mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_AUTO); 55 | updatePreview(); 56 | } 57 | 58 | @Override 59 | public void doInProgress2() { 60 | mTextView.setText("多云"); 61 | mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_CLOUDY_DAYLIGHT); 62 | updatePreview(); 63 | } 64 | 65 | @Override 66 | public void doInProgress3() { 67 | mTextView.setText("白天"); 68 | mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_DAYLIGHT); 69 | updatePreview(); 70 | } 71 | 72 | 73 | @Override 74 | public void doInProgress4() { 75 | mTextView.setText("日光灯"); 76 | mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_FLUORESCENT); 77 | updatePreview(); 78 | } 79 | 80 | @Override 81 | public void doInProgress5() { 82 | mTextView.setText("白炽灯"); 83 | mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_INCANDESCENT); 84 | updatePreview(); 85 | } 86 | 87 | @Override 88 | public void doInProgress6() { 89 | mTextView.setText("阴影"); 90 | mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_SHADE); 91 | updatePreview(); 92 | } 93 | 94 | @Override 95 | public void doInProgress7() { 96 | mTextView.setText("黄昏"); 97 | mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_TWILIGHT); 98 | updatePreview(); 99 | } 100 | 101 | @Override 102 | public void doInProgress8() { 103 | mTextView.setText("暖光"); 104 | mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_WARM_FLUORESCENT); 105 | updatePreview(); 106 | } 107 | 108 | @Override 109 | public void onStopTrackingTouch(int num) { 110 | switch (num) { 111 | case 0: 112 | mTextView.setText("自动"); 113 | mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_AUTO); 114 | break; 115 | case 10: 116 | mTextView.setText("多云"); 117 | mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_CLOUDY_DAYLIGHT); 118 | break; 119 | case 20: 120 | mTextView.setText("白天"); 121 | mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_DAYLIGHT); 122 | break; 123 | case 30: 124 | mTextView.setText("日光灯"); 125 | mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_FLUORESCENT); 126 | break; 127 | case 40: 128 | mTextView.setText("白炽灯"); 129 | mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_INCANDESCENT); 130 | break; 131 | case 50: 132 | mTextView.setText("阴影"); 133 | mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_SHADE); 134 | break; 135 | case 60: 136 | mTextView.setText("黄昏"); 137 | mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_TWILIGHT); 138 | break; 139 | case 70: 140 | mTextView.setText("暖光"); 141 | mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_WARM_FLUORESCENT); 142 | break; 143 | } 144 | updatePreview(); 145 | mTextView.startAnimation(mAlphaOutAnimation); 146 | mTextView.setVisibility(View.INVISIBLE); 147 | } 148 | 149 | @Override 150 | public void onStartTrackingTouch(SeekBar seekBar) { 151 | mTextView.setVisibility(View.VISIBLE); 152 | mTextView.startAnimation(mAlphaInAnimation); 153 | } 154 | 155 | /** 156 | * 更新预览 157 | */ 158 | private void updatePreview() { 159 | try { 160 | mCameraCaptureSession.setRepeatingRequest(mPreviewBuilder.build(), mPreviewSessionCallback, mHandler); 161 | } catch (CameraAccessException e) { 162 | e.printStackTrace(); 163 | } catch (Exception e) { 164 | e.printStackTrace(); 165 | Log.i("updatePreview", "ExceptionExceptionException"); 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/view/CameraV2GLSurfaceView.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.view; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLSurfaceView; 5 | 6 | import camera.cn.cameramaster.util.render.CameraV2Renderer; 7 | import camera.cn.cameramaster.util.CameraV2; 8 | 9 | 10 | /** 11 | * CameraV2 GLSurfaceView 12 | * 参考url : [https://blog.csdn.net/lb377463323/article/details/78054892] 13 | * 14 | * @date 2019年2月12日 13:41:16 15 | * @author ymc 16 | */ 17 | 18 | public class CameraV2GLSurfaceView extends GLSurfaceView { 19 | public static boolean shouldTakePic = false; 20 | 21 | public void init(CameraV2 camera, boolean isPreviewStarted, Context context) { 22 | setEGLContextClientVersion(2); 23 | CameraV2Renderer mCameraV2Renderer = new CameraV2Renderer(); 24 | mCameraV2Renderer.init(this, camera, isPreviewStarted, context); 25 | setRenderer(mCameraV2Renderer); 26 | setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); 27 | } 28 | 29 | public CameraV2GLSurfaceView(Context context) { 30 | super(context); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/view/ShowSurfaceView.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.view; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.util.AttributeSet; 9 | import android.view.SurfaceHolder; 10 | import android.view.SurfaceView; 11 | 12 | /** 13 | * @packageName: cn.tongue.tonguecamera.view 14 | * @fileName: ShowSurfaceView 15 | * @date: 2019/3/7 13:17 16 | * @author: ymc 17 | * @QQ:745612618 18 | */ 19 | 20 | public class ShowSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable { 21 | private SurfaceHolder mSurfaceHolder; 22 | /** 23 | * 绘图的Canvas 24 | */ 25 | private Canvas mCanvas; 26 | /** 27 | * 子线程标志位 28 | */ 29 | private boolean mIsDrawing; 30 | private Bitmap bitmap; 31 | private Paint mPaint; 32 | 33 | public ShowSurfaceView(Context context) { 34 | this(context, null); 35 | } 36 | 37 | public ShowSurfaceView(Context context, AttributeSet attrs) { 38 | this(context, attrs, 0); 39 | } 40 | 41 | public ShowSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) { 42 | super(context, attrs, defStyleAttr); 43 | mSurfaceHolder = getHolder(); 44 | mSurfaceHolder.addCallback(this); 45 | setFocusable(true); 46 | setKeepScreenOn(true); 47 | setFocusableInTouchMode(true); 48 | mPaint = new Paint(); 49 | mPaint.setColor(Color.BLACK); 50 | mPaint.setStyle(Paint.Style.STROKE); 51 | mPaint.setAntiAlias(true); 52 | mPaint.setStrokeWidth(5); 53 | } 54 | 55 | @Override 56 | public void surfaceCreated(SurfaceHolder holder) { 57 | mIsDrawing = true; 58 | //开启子线程 59 | new Thread(this).start(); 60 | } 61 | 62 | @Override 63 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 64 | //改变 65 | } 66 | 67 | @Override 68 | public void surfaceDestroyed(SurfaceHolder holder) { 69 | mIsDrawing = false; 70 | } 71 | 72 | @Override 73 | public void run() { 74 | while (mIsDrawing) { 75 | drawSomething(); 76 | } 77 | } 78 | 79 | //绘图逻辑 80 | private void drawSomething() { 81 | try { 82 | //获得canvas对象 83 | mCanvas = mSurfaceHolder.lockCanvas(); 84 | // Bitmap bitmap1= BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher); 85 | if (bitmap != null) { 86 | mCanvas.drawBitmap(bitmap, 0, 0, mPaint); 87 | } 88 | //绘图 89 | } catch (Exception e) { 90 | 91 | } finally { 92 | if (mCanvas != null) { 93 | //释放canvas对象并提交画布 94 | mSurfaceHolder.unlockCanvasAndPost(mCanvas); 95 | } 96 | } 97 | } 98 | 99 | public Bitmap getBitmap() { 100 | return bitmap; 101 | } 102 | 103 | public void setBitmap(Bitmap bitmap) { 104 | this.bitmap = bitmap; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /app/src/main/java/camera/cn/cameramaster/view/SleepThread.java: -------------------------------------------------------------------------------- 1 | package camera.cn.cameramaster.view; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | 6 | /** 7 | * 睡眠线程 8 | * 9 | * @author ymc 10 | */ 11 | public class SleepThread implements Runnable { 12 | private Handler mMainHandler; 13 | private int what; 14 | private long mTime; 15 | private Object mObject; 16 | 17 | public SleepThread(Handler mainHandler, int what, long mTime, Object mObject) { 18 | this.mMainHandler = mainHandler; 19 | this.what = what; 20 | this.mTime = mTime; 21 | this.mObject = mObject; 22 | } 23 | 24 | @Override 25 | public void run() { 26 | try { 27 | Thread.sleep(mTime); 28 | } catch (InterruptedException e) { 29 | e.printStackTrace(); 30 | } 31 | Message message = mMainHandler.obtainMessage(); 32 | message.what = what; 33 | message.obj = mObject; 34 | mMainHandler.sendMessage(message); 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/res/anim/alpha_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/anim/alpha_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_camera.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_fouces.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_camera.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_camera.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 17 | 18 | 19 | 20 | 26 | 27 | 32 | 33 | 34 | 35 | 36 | 42 | 43 | 52 | 53 | 61 | 62 | 63 | 64 | 73 | 74 | 81 | 82 | 86 | 87 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_camera2.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 15 | 16 | 17 | 18 | 24 | 25 | 34 | 35 | 43 | 44 | 45 | 46 | 55 | 56 | 63 | 64 | 68 | 69 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_camera_sv.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 14 | 15 | 21 | 22 | 31 | 32 | 40 | 41 | 42 | 43 | 53 | 54 | 61 | 62 | 66 | 67 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_look_camera.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 8 | 11 | 12 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 |