├── .gitignore ├── .idea ├── checkstyle-idea.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── libs │ ├── androidutils.jar │ ├── libutils.jar │ ├── libvlc-3.0.0.aar │ ├── libvlc-3.0.0_32.aar │ └── xutils.jar ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── cayden │ │ └── face │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── mtcnn_freezed_model.pb │ ├── java │ │ └── com │ │ │ └── cayden │ │ │ └── face │ │ │ ├── FaceApplication.java │ │ │ ├── FaceDB.java │ │ │ ├── FaceManagerActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── facenet │ │ │ ├── Box.java │ │ │ ├── FaceFeature.java │ │ │ ├── Facenet.java │ │ │ ├── MTCNN.java │ │ │ └── Utils.java │ │ │ ├── stream │ │ │ ├── ExtByteTools.java │ │ │ ├── ExtInputStream.java │ │ │ └── ExtOutputStream.java │ │ │ ├── utils │ │ │ ├── ImageUtils.java │ │ │ └── NV21ToBitmap.java │ │ │ └── vlc │ │ │ ├── AppBeanService.java │ │ │ ├── ConstData.java │ │ │ ├── Rtsp.java │ │ │ ├── RtspCallbackInterface.java │ │ │ ├── UdpPlayerApplication.java │ │ │ ├── UrlInfo.java │ │ │ └── UrlInfoService.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_register.xml │ │ ├── activity_vlc_player.xml │ │ └── camera_view.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── btn_main.png │ │ ├── face_reco_bg.png │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── cayden │ └── face │ └── 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 | *.iml 11 | .gradle 12 | /local.properties 13 | /.idea/workspace.xml 14 | /.idea/libraries 15 | .DS_Store 16 | /build 17 | /captures 18 | .gradle 19 | /local.properties 20 | /.idea/workspace.xml 21 | /.idea/libraries 22 | .DS_Store 23 | /build 24 | /captures 25 | # Local per-repo rules can be added to the .git/info/exclude file in your 26 | # repo. These rules are not committed with the repo so they are not shared 27 | # with others. This method can be used for locally-generated files that you 28 | # don’t expect other users to generate, like files created by your editor. 29 | .settings 30 | .classpath 31 | bin 32 | Debug 33 | obj 34 | coverage 35 | coverage.ec 36 | coverage.em 37 | gen 38 | javadoc 39 | junit-report.xml 40 | lint-results.*ml 41 | lint-results_files 42 | local.properties 43 | monkey.txt 44 | *~ 45 | *.iws 46 | atlassian-ide-plugin.xml 47 | target 48 | build 49 | .gradle 50 | out 51 | build.xml 52 | proguard-project.txt 53 | .idea/ 54 | *.iml 55 | # Built application files 56 | *.apk 57 | *.ap_ 58 | 59 | # Files for the Dalvik VM 60 | *.dex 61 | 62 | # Java class files 63 | *.class 64 | 65 | # Generated files 66 | bin/ 67 | gen/ 68 | 69 | # Gradle files 70 | .gradle/ 71 | build/ 72 | 73 | # Local configuration file (sdk path, etc) 74 | local.properties 75 | 76 | # Proguard folder generated by Eclipse 77 | proguard/ 78 | 79 | # Log Files 80 | *.log 81 | # Built application files 82 | *.apk 83 | *.ap_ 84 | 85 | # Files for the ART/Dalvik VM 86 | *.dex 87 | 88 | # Java class files 89 | *.class 90 | 91 | # Generated files 92 | bin/ 93 | gen/ 94 | out/ 95 | 96 | # Gradle files 97 | .gradle/ 98 | build/ 99 | 100 | # Local configuration file (sdk path, etc) 101 | local.properties 102 | 103 | # Proguard folder generated by Eclipse 104 | proguard/ 105 | 106 | # Log Files 107 | *.log 108 | 109 | # Android Studio Navigation editor temp files 110 | .navigation/ 111 | 112 | # Android Studio captures folder 113 | captures/ 114 | 115 | # Intellij 116 | *.iml 117 | .idea/workspace.xml 118 | .idea/tasks.xml 119 | .idea/gradle.xml 120 | .idea/dictionaries 121 | .idea/libraries 122 | 123 | # Keystore files 124 | *.jks 125 | 126 | # External native build folder generated in Android Studio 2.2 and later 127 | .externalNativeBuild 128 | 129 | # Google Services (e.g. APIs or Firebase) 130 | google-services.json 131 | 132 | # Freeline 133 | freeline.py 134 | freeline/ 135 | freeline_project_description.json -------------------------------------------------------------------------------- /.idea/checkstyle-idea.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 35 | 36 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 84 | 94 | 95 | 96 | 97 | 98 | 99 | 101 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # facesample 2 | 3 | 本项目主要基于vlc来播放流媒体视频 4 | 可以入QQ群参与讨论:735436509 5 | 6 | 主要包含以下内容 7 | 8 | - 1、使用已经编译的libvlc来播放流媒体视频 9 | - 2、使用MTCNN进行人脸识别并标记人脸 10 | - 3、保存标记的人脸图片 11 | - 4、使用FACENET进行人脸比对 12 | - 未完待续... 13 | 14 | 15 | ### v1.0.3 16 | - 1, 通过FACENET获取脸部特征数据 17 | - 2, 人脸比对,找出相似度最高的人 18 | 19 | 20 | ### v1.0.2 21 | - 1, 通过MTCNN检测人脸 22 | - 2, 对人脸进行标记 23 | 24 | 25 | ### v1.0.1 26 | - 1, 获取返回的视频流数据 27 | - 2, 将数据nv12转换为nv21,并保存图片 28 | 29 | ### v1.0.0 30 | - 1, added libvlc 31 | - 2, support for playing rtsp video stream 32 | 33 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 27 5 | buildToolsVersion '27.0.3' 6 | defaultConfig { 7 | applicationId "com.cayden.face" 8 | minSdkVersion 19 9 | targetSdkVersion 27 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | android { 23 | compileOptions { 24 | sourceCompatibility JavaVersion.VERSION_1_8 25 | targetCompatibility JavaVersion.VERSION_1_8 26 | } 27 | } 28 | 29 | repositories { 30 | flatDir { 31 | dirs 'libs' 32 | } 33 | maven { 34 | url "http://dl.bintray.com/jlmd/maven" 35 | } 36 | } 37 | 38 | dependencies { 39 | implementation fileTree(include: ['*.jar'], dir: 'libs') 40 | implementation 'com.android.support:appcompat-v7:27.1.1' 41 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 42 | testImplementation 'junit:junit:4.12' 43 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 44 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 45 | compile(name: 'libvlc-3.0.0', ext: 'aar') 46 | implementation files('libs/androidutils.jar') 47 | compile 'org.tensorflow:tensorflow-android:+' 48 | implementation files('libs/libutils.jar') 49 | } 50 | -------------------------------------------------------------------------------- /app/libs/androidutils.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cayden/facesample/70b5eebc4fb7349eb46992daa2d30501c510c48d/app/libs/androidutils.jar -------------------------------------------------------------------------------- /app/libs/libutils.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cayden/facesample/70b5eebc4fb7349eb46992daa2d30501c510c48d/app/libs/libutils.jar -------------------------------------------------------------------------------- /app/libs/libvlc-3.0.0.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cayden/facesample/70b5eebc4fb7349eb46992daa2d30501c510c48d/app/libs/libvlc-3.0.0.aar -------------------------------------------------------------------------------- /app/libs/libvlc-3.0.0_32.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cayden/facesample/70b5eebc4fb7349eb46992daa2d30501c510c48d/app/libs/libvlc-3.0.0_32.aar -------------------------------------------------------------------------------- /app/libs/xutils.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cayden/facesample/70b5eebc4fb7349eb46992daa2d30501c510c48d/app/libs/xutils.jar -------------------------------------------------------------------------------- /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/com/cayden/face/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.cayden.face; 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("com.cayden.face", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/assets/mtcnn_freezed_model.pb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cayden/facesample/70b5eebc4fb7349eb46992daa2d30501c510c48d/app/src/main/assets/mtcnn_freezed_model.pb -------------------------------------------------------------------------------- /app/src/main/java/com/cayden/face/FaceApplication.java: -------------------------------------------------------------------------------- 1 | package com.cayden.face; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.graphics.Matrix; 8 | import android.media.ExifInterface; 9 | import android.net.Uri; 10 | import android.os.Environment; 11 | import android.util.Log; 12 | 13 | 14 | /** 15 | * Created by caydencui on 2018/9/6. 16 | */ 17 | 18 | public class FaceApplication extends Application { 19 | private static final String TAG = "FaceApplication"; 20 | public FaceDB mFaceDB; 21 | Uri mImage; 22 | private static FaceApplication instance; 23 | 24 | //绘制左右翻转 25 | public static final boolean yu = true; 26 | 27 | public FaceApplication(){ 28 | 29 | } 30 | 31 | @Override 32 | public void onCreate() { 33 | super.onCreate(); 34 | instance=this; 35 | mFaceDB= FaceDB.getInstance(); 36 | mFaceDB.init(Environment.getExternalStorageDirectory().getPath() + "/FaceDetect"); 37 | mImage = null; 38 | } 39 | 40 | // 获取Application 41 | public static Context getMyApplication() { 42 | return instance; 43 | } 44 | 45 | public void setCaptureImage(Uri uri) { 46 | mImage = uri; 47 | } 48 | 49 | public Uri getCaptureImage() { 50 | return mImage; 51 | } 52 | 53 | /** 54 | * @param path 55 | * @return 56 | */ 57 | public static Bitmap decodeImage(String path) { 58 | Bitmap res; 59 | try { 60 | ExifInterface exif = new ExifInterface(path); 61 | int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); 62 | 63 | BitmapFactory.Options op = new BitmapFactory.Options(); 64 | op.inSampleSize = 1; 65 | op.inJustDecodeBounds = false; 66 | //op.inMutable = true; 67 | res = BitmapFactory.decodeFile(path, op); 68 | //rotate and scale. 69 | Matrix matrix = new Matrix(); 70 | 71 | if (orientation == ExifInterface.ORIENTATION_ROTATE_90) { 72 | matrix.postRotate(90); 73 | } else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) { 74 | matrix.postRotate(180); 75 | } else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) { 76 | matrix.postRotate(270); 77 | } 78 | 79 | Bitmap temp = Bitmap.createBitmap(res, 0, 0, res.getWidth(), res.getHeight(), matrix, true); 80 | Log.d(TAG, "check target Image:" + temp.getWidth() + "X" + temp.getHeight()); 81 | 82 | if (!temp.equals(res)) { 83 | res.recycle(); 84 | } 85 | return temp; 86 | } catch (Exception e) { 87 | e.printStackTrace(); 88 | } 89 | return null; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/com/cayden/face/FaceDB.java: -------------------------------------------------------------------------------- 1 | package com.cayden.face; 2 | 3 | import android.util.Log; 4 | 5 | 6 | import com.cayden.face.facenet.FaceFeature; 7 | import com.cayden.face.stream.ExtInputStream; 8 | import com.cayden.face.stream.ExtOutputStream; 9 | 10 | import java.io.File; 11 | import java.io.FileInputStream; 12 | import java.io.FileNotFoundException; 13 | import java.io.FileOutputStream; 14 | import java.io.IOException; 15 | import java.io.RandomAccessFile; 16 | import java.nio.ByteBuffer; 17 | import java.nio.channels.FileChannel; 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | /** 22 | * Created by caydencui on 2018/9/6. 23 | */ 24 | 25 | public class FaceDB { 26 | private final String TAG = this.getClass().toString(); 27 | 28 | String mDBPath; 29 | public List mRegister; 30 | private FaceDB() { 31 | 32 | } 33 | 34 | private static class SingletonInstance { 35 | private static final FaceDB INSTANCE = new FaceDB(); 36 | } 37 | 38 | public static FaceDB getInstance() { 39 | return SingletonInstance.INSTANCE; 40 | } 41 | 42 | public void init(String path){ 43 | mDBPath = path; 44 | mRegister = new ArrayList<>(); 45 | } 46 | 47 | public class FaceRegist { 48 | public String mName; 49 | public FaceFeature faceFeature; 50 | 51 | public FaceRegist(String name) { 52 | mName = name; 53 | faceFeature = new FaceFeature(); 54 | } 55 | } 56 | 57 | private boolean saveInfo() { 58 | try { 59 | Log.d(TAG, "mDBPath=" +mDBPath + "/face.txt"); 60 | FileOutputStream fs = new FileOutputStream(mDBPath + "/face.txt"); 61 | ExtOutputStream bos = new ExtOutputStream(fs); 62 | bos.writeString( "tusi-face-v1.0.0," + 1); 63 | bos.close(); 64 | fs.close(); 65 | return true; 66 | } catch (FileNotFoundException e) { 67 | e.printStackTrace(); 68 | } catch (IOException e) { 69 | e.printStackTrace(); 70 | } 71 | return false; 72 | } 73 | 74 | /** 75 | * 加载数据 76 | * @return 77 | */ 78 | private boolean loadInfo() { 79 | if (!mRegister.isEmpty()) { 80 | return false; 81 | } 82 | try { 83 | File file=new File(mDBPath ); 84 | if(!file.exists()){ 85 | file.mkdir(); 86 | 87 | } 88 | FileInputStream fs = new FileInputStream(mDBPath + "/face.txt"); 89 | ExtInputStream bos = new ExtInputStream(fs); 90 | //load version 91 | String version_saved = bos.readString(); 92 | 93 | //load all regist name. 94 | if (version_saved != null) { 95 | for (String name = bos.readString(); name != null; name = bos.readString()){ 96 | if (new File(mDBPath + "/" + name + ".data").exists()) { 97 | mRegister.add(new FaceRegist(new String(name))); 98 | } 99 | } 100 | } 101 | bos.close(); 102 | fs.close(); 103 | return true; 104 | } catch (FileNotFoundException e) { 105 | e.printStackTrace(); 106 | } catch (IOException e) { 107 | e.printStackTrace(); 108 | } 109 | return false; 110 | } 111 | 112 | /** 113 | * 加载人脸数据 114 | * @return 115 | */ 116 | public boolean loadFaces(){ 117 | if (loadInfo()) { 118 | try { 119 | for (FaceRegist face : mRegister) { 120 | Log.d(TAG, "load name:" + face.mName + "'s face feature data."); 121 | FileInputStream fs = new FileInputStream(mDBPath + "/" + face.mName + ".data"); 122 | 123 | float [] fea= readFloatFromData(mDBPath + "/" + face.mName + ".data",512); 124 | face.faceFeature.setFea(fea); 125 | 126 | } 127 | Log.d(TAG, "load mRegister: size = " + mRegister.size()); 128 | return true; 129 | } 130 | catch (Exception e) { 131 | e.printStackTrace(); 132 | } 133 | } 134 | return false; 135 | } 136 | 137 | /** 138 | * 添加人脸数据信息 139 | * @param name 140 | * @param face 141 | */ 142 | public void addFace(String name, FaceFeature face) { 143 | try { 144 | //check if already registered. 145 | boolean add = true; 146 | for (FaceRegist frface : mRegister) { 147 | if (frface.mName.equals(name)) { 148 | frface.faceFeature=face; 149 | add = false; 150 | break; 151 | } 152 | } 153 | if (add) { // not registered. 154 | FaceRegist frface = new FaceRegist(name); 155 | frface.faceFeature=face; 156 | mRegister.add(frface); 157 | } 158 | 159 | if (saveInfo()) { 160 | //update all names 161 | FileOutputStream fs = new FileOutputStream(mDBPath + "/face.txt", true); 162 | ExtOutputStream bos = new ExtOutputStream(fs); 163 | for (FaceRegist frface : mRegister) { 164 | bos.writeString(frface.mName); 165 | } 166 | bos.close(); 167 | fs.close(); 168 | 169 | //save new feature 170 | writeFloatToData(face.getFeature(),mDBPath + "/" + name + ".data",512); 171 | 172 | } 173 | } catch (FileNotFoundException e) { 174 | e.printStackTrace(); 175 | } catch (IOException e) { 176 | e.printStackTrace(); 177 | } 178 | } 179 | 180 | /** 181 | * 删除对应人脸信息 182 | * @param name 183 | * @return 184 | */ 185 | public boolean delete(String name) { 186 | try { 187 | //check if already registered. 188 | boolean find = false; 189 | for (FaceRegist frface : mRegister) { 190 | if (frface.mName.equals(name)) { 191 | File delfile = new File(mDBPath + "/" + name + ".data"); 192 | if (delfile.exists()) { 193 | delfile.delete(); 194 | } 195 | mRegister.remove(frface); 196 | find = true; 197 | break; 198 | } 199 | } 200 | 201 | if (find) { 202 | if (saveInfo()) { 203 | //update all names 204 | FileOutputStream fs = new FileOutputStream(mDBPath + "/face.txt", true); 205 | ExtOutputStream bos = new ExtOutputStream(fs); 206 | for (FaceRegist frface : mRegister) { 207 | bos.writeString(frface.mName); 208 | } 209 | bos.close(); 210 | fs.close(); 211 | } 212 | } 213 | return find; 214 | } catch (FileNotFoundException e) { 215 | e.printStackTrace(); 216 | } catch (IOException e) { 217 | e.printStackTrace(); 218 | } 219 | return false; 220 | } 221 | 222 | 223 | /** 224 | * 将float[]写入文件 225 | * @param verts 226 | * @param gcodeFile 227 | * @param count 228 | */ 229 | private void writeFloatToData(float[] verts, String gcodeFile, int count) { 230 | try { 231 | RandomAccessFile aFile = new RandomAccessFile(gcodeFile, "rw"); 232 | FileChannel outChannel = aFile.getChannel(); 233 | //one float 4 bytes 234 | ByteBuffer buf = ByteBuffer.allocate(4 * count * 3 * 3); 235 | buf.clear(); 236 | buf.asFloatBuffer().put(verts); 237 | //while(buf.hasRemaining()) 238 | { 239 | outChannel.write(buf); 240 | } 241 | //outChannel.close(); 242 | buf.rewind(); 243 | outChannel.close(); 244 | } catch (IOException ex) { 245 | System.err.println(ex.getMessage()); 246 | } 247 | } 248 | 249 | /** 250 | * 读取文件返回float[] 251 | * @param gcodeFile 252 | * @param Count 253 | * @return 254 | */ 255 | private float[] readFloatFromData(String gcodeFile, int Count) { 256 | float[] verts = new float[Count * 3 * 3]; 257 | try { 258 | RandomAccessFile rFile = new RandomAccessFile(gcodeFile, "rw"); 259 | FileChannel inChannel = rFile.getChannel(); 260 | ByteBuffer buf_in = ByteBuffer.allocate(3 * 3 * Count * 4); 261 | buf_in.clear(); 262 | inChannel.read(buf_in); 263 | buf_in.rewind(); 264 | buf_in.asFloatBuffer().get(verts); 265 | inChannel.close(); 266 | } catch (IOException ex) { 267 | System.err.println(ex.getMessage()); 268 | } 269 | return verts; 270 | } 271 | 272 | 273 | } 274 | -------------------------------------------------------------------------------- /app/src/main/java/com/cayden/face/FaceManagerActivity.java: -------------------------------------------------------------------------------- 1 | package com.cayden.face; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.ContentUris; 5 | import android.content.Intent; 6 | import android.database.Cursor; 7 | import android.graphics.Bitmap; 8 | import android.graphics.BitmapFactory; 9 | import android.graphics.Rect; 10 | import android.net.Uri; 11 | import android.os.Build; 12 | import android.os.Bundle; 13 | import android.os.Environment; 14 | import android.provider.DocumentsContract; 15 | import android.provider.MediaStore; 16 | import android.support.annotation.Nullable; 17 | import android.support.v7.app.AppCompatActivity; 18 | import android.text.TextUtils; 19 | import android.util.Log; 20 | import android.view.View; 21 | import android.widget.Button; 22 | import android.widget.EditText; 23 | import android.widget.ImageView; 24 | import android.widget.Toast; 25 | 26 | import com.cayden.face.facenet.Box; 27 | import com.cayden.face.facenet.FaceFeature; 28 | import com.cayden.face.facenet.Facenet; 29 | import com.cayden.face.facenet.MTCNN; 30 | import com.cayden.face.facenet.Utils; 31 | 32 | import java.io.File; 33 | import java.io.IOException; 34 | import java.util.Vector; 35 | 36 | /** 37 | * Created by caydencui on 2018/12/29. 38 | */ 39 | 40 | public class FaceManagerActivity extends AppCompatActivity implements View.OnClickListener { 41 | 42 | public static final int CHOOSE_PHOTO=0; 43 | private Button btn_select,btn_register; 44 | private EditText edit_name; 45 | private ImageView iv_head; 46 | private Uri imageUri; 47 | private Facenet facenet; 48 | private MTCNN mtcnn; 49 | private Bitmap bitmap=null;//选择的图片 50 | @Override 51 | protected void onCreate(@Nullable Bundle savedInstanceState) { 52 | super.onCreate(savedInstanceState); 53 | setContentView(R.layout.activity_register); 54 | facenet=Facenet.getInstance(); 55 | mtcnn = MTCNN.getInstance(); 56 | btn_select=(Button)findViewById(R.id.pic_select); 57 | btn_register=(Button)findViewById(R.id.pic_register); 58 | btn_select.setOnClickListener(this); 59 | btn_register.setOnClickListener(this); 60 | iv_head=(ImageView)findViewById(R.id.iv_head); 61 | edit_name=(EditText)findViewById(R.id.edit_name); 62 | 63 | } 64 | 65 | @Override 66 | public void onClick(View v) { 67 | switch (v.getId()){ 68 | case R.id.pic_select: 69 | choosePhoto(); 70 | break; 71 | case R.id.pic_register: 72 | registerFace(); 73 | break; 74 | } 75 | } 76 | 77 | 78 | public Bitmap detectFaces(){ 79 | if(null==bitmap)return null; 80 | 81 | Vector boxes=mtcnn.detectFaces(bitmap,40); 82 | if (boxes.size()==0) return null; 83 | for (int i=0;i boxes = mtcnn.detectFaces(bitmap, 20); 171 | 172 | drawAnim(boxes, draw_view, scale_bit, 1, ""); 173 | 174 | if (boxes.size()==0) return ; 175 | for (int i=0;i mResgist =FaceDB.getInstance().mRegister; 191 | double tempScore=-1; 192 | for(int i=0;itemp){ 203 | foundName=faceRegist.mName; 204 | tempScore=temp; 205 | } 206 | } 207 | Log.d(TAG,">>>>>>>>>>temp="+temp+",tempScore="+tempScore+",foundName:"+foundName); 208 | } 209 | cmp=tempScore; 210 | runOnUiThread(new Runnable() { 211 | @Override 212 | public void run() { 213 | 214 | tv_result.setText(String.format("名字:%s 相似度 : %.4f", foundName,cmp) ); 215 | } 216 | }); 217 | } 218 | 219 | } 220 | }); 221 | 222 | } 223 | 224 | 225 | protected void drawAnim(Vector faces, SurfaceView outputView, float scale_bit, int cameraId, String fps) { 226 | Paint paint = new Paint(); 227 | Canvas canvas = ((SurfaceView) outputView).getHolder().lockCanvas(); 228 | if (canvas != null) { 229 | try { 230 | int viewH = outputView.getHeight(); 231 | int viewW = outputView.getWidth(); 232 | // DLog.d("viewW:"+viewW+",viewH:"+viewH); 233 | canvas.drawColor(0, PorterDuff.Mode.CLEAR); 234 | if (faces == null || faces.size() == 0) return; 235 | for (int i = 0; i < faces.size(); i++) { 236 | paint.setColor(Color.BLUE); 237 | int size = DisplayUtil.dip2px(this, 3); 238 | paint.setStrokeWidth(size); 239 | paint.setStyle(Paint.Style.STROKE); 240 | Box box = faces.get(i); 241 | float[] rect = box.transform2float(); 242 | float x1 = rect[0] * scale_bit; 243 | float y1 = rect[1] * scale_bit; 244 | float rect_width = rect[2] * 0.5F; 245 | RectF rectf = new RectF(x1, y1, x1 + rect_width, y1 + rect_width); 246 | canvas.drawRect(rectf, paint); 247 | } 248 | 249 | } catch (Exception e) { 250 | e.printStackTrace(); 251 | } finally { 252 | ((SurfaceView) outputView).getHolder().unlockCanvasAndPost(canvas); 253 | } 254 | } 255 | } 256 | 257 | 258 | public static String tempTarget = Environment.getExternalStorageDirectory() + File.separator + "CWModels" + File.separator + "Register.jpg"; 259 | 260 | /** 261 | * 保存图片 262 | * 263 | * @param data 264 | */ 265 | public void mPictureSave(byte[] data) { 266 | byte[] NV21 = new byte[data.length]; 267 | NV12ToNV21(data, NV21, ConstData.DEFAULT_PREVIEW_WIDTH, ConstData.DEFAULT_PREVIEW_HEIGHT); 268 | YuvImage yuvImage = new YuvImage(NV21, ImageFormat.NV21, ConstData.DEFAULT_PREVIEW_WIDTH, ConstData.DEFAULT_PREVIEW_HEIGHT, null); 269 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 270 | yuvImage.compressToJpeg(new Rect(0, 0, ConstData.DEFAULT_PREVIEW_WIDTH, ConstData.DEFAULT_PREVIEW_HEIGHT), 80, baos); 271 | byte[] jdata = baos.toByteArray(); 272 | Bitmap bitmap = BitmapFactory.decodeByteArray(jdata, 0, jdata.length); 273 | File file = null; 274 | file = new File(tempTarget); 275 | FileOutputStream fileOutputStream = null; 276 | try { 277 | fileOutputStream = new FileOutputStream(file); 278 | fileOutputStream.write(jdata); 279 | fileOutputStream.close(); 280 | 281 | } catch (IOException e) { 282 | e.printStackTrace(); 283 | } 284 | 285 | } 286 | 287 | private void NV12ToNV21(byte[] nv12, byte[] nv21, int width, int height) { 288 | if (nv21 == null || nv12 == null) return; 289 | int framesize = width * height; 290 | int i = 0, j = 0; 291 | //System.arraycopy(nv21, test, nv12, test, framesize); 292 | for (i = 0; i < framesize; i++) { 293 | nv21[i] = nv12[i]; 294 | } 295 | for (j = 0; j < framesize / 2; j += 2) { 296 | nv21[framesize + j] = nv12[j + framesize + 1]; 297 | } 298 | for (j = 0; j < framesize / 2; j += 2) { 299 | nv21[framesize + j + 1] = nv12[j + framesize]; 300 | } 301 | } 302 | 303 | private View.OnClickListener onClickListener_run = new View.OnClickListener() { 304 | @Override 305 | public void onClick(View v) { 306 | 307 | 308 | // mRegisterStatus.setText(""); 309 | // mEditText.setText(""); 310 | mRun_verify.setClickable(false); 311 | //mBackgroundHandler1.post(new ImageProcess()); 312 | 313 | } 314 | }; 315 | private View.OnClickListener onClickListener_PicSave = new View.OnClickListener() { 316 | @Override 317 | public void onClick(View v) { 318 | isSave = true; 319 | } 320 | }; 321 | 322 | private View.OnClickListener onClickListener_StartPlay = new View.OnClickListener() { 323 | @Override 324 | public void onClick(View v) { 325 | String netAddress = mEditNetAddress.getText().toString().trim(); 326 | if (!TextUtils.isEmpty(netAddress)) { 327 | UrlInfo urlInfo = new UrlInfo(); 328 | urlInfo.setUrl(netAddress); 329 | mUrlInfoService.save(urlInfo); 330 | Rtsp.mRun = true; 331 | isStart=true; 332 | mNxpRtsp.SetUrl(netAddress); 333 | mNxpRtsp.init(null, mVideoTexture); 334 | mNxpRtsp.play(); 335 | } 336 | 337 | } 338 | }; 339 | 340 | private View.OnClickListener onClickListener_Stop = new View.OnClickListener() { 341 | @Override 342 | public void onClick(View v) { 343 | mNxpRtsp.stop(); 344 | 345 | } 346 | }; 347 | 348 | 349 | @Override 350 | protected void onDestroy() { 351 | super.onDestroy(); 352 | if(null!=mNxpRtsp&&isStart){ 353 | Rtsp.mRun = false; 354 | mNxpRtsp.stop(); 355 | } 356 | 357 | } 358 | } 359 | -------------------------------------------------------------------------------- /app/src/main/java/com/cayden/face/facenet/Box.java: -------------------------------------------------------------------------------- 1 | package com.cayden.face.facenet; 2 | 3 | import android.graphics.Point; 4 | import android.graphics.Rect; 5 | 6 | import static java.lang.Math.max; 7 | 8 | /** 9 | * Created by caydencui on 2018/9/6. 10 | */ 11 | public class Box { 12 | public int[] box; //left:box[0],top:box[1],right:box[2],bottom:box[3] 13 | public float score; //probability 14 | public float[] bbr; //bounding box regression 15 | public boolean deleted; 16 | public Point[] landmark; //facial landmark.只有ONet输出Landmark 17 | Box(){ 18 | box=new int[4]; 19 | bbr=new float[4]; 20 | deleted=false; 21 | landmark=new Point[5]; 22 | } 23 | public int left(){return box[0];} 24 | public int right(){return box[2];} 25 | public int top(){return box[1];} 26 | public int bottom(){return box[2];} 27 | public int width(){return box[2]-box[0]+1;} 28 | public int height(){return box[3]-box[1]+1;} 29 | //转为rect 30 | public Rect transform2Rect(){ 31 | Rect rect=new Rect(); 32 | rect.left= Math.round(box[0]); 33 | rect.top= Math.round(box[1]); 34 | rect.right= Math.round(box[2]); 35 | rect.bottom= Math.round(box[3]); 36 | return rect; 37 | } 38 | 39 | public float[] transform2float(){ 40 | float [] floats=new float[4]; 41 | 42 | floats[0]= Math.round(box[0]); 43 | floats[1]= Math.round(box[1]); 44 | floats[2]= Math.round(box[2]); 45 | floats[3]= Math.round(box[3]); 46 | 47 | return floats; 48 | } 49 | //面积 50 | public int area(){ 51 | return width()*height(); 52 | } 53 | //Bounding Box Regression 54 | public void calibrate(){ 55 | int w=box[2]-box[0]+1; 56 | int h=box[3]-box[1]+1; 57 | box[0]=(int)(box[0]+w*bbr[0]); 58 | box[1]=(int)(box[1]+h*bbr[1]); 59 | box[2]=(int)(box[2]+w*bbr[2]); 60 | box[3]=(int)(box[3]+h*bbr[3]); 61 | for (int i=0;i<4;i++) bbr[i]=0.0f; 62 | } 63 | //当前box转为正方形 64 | public void toSquareShape(){ 65 | int w=width(); 66 | int h=height(); 67 | if (w>h){ 68 | box[1]-=(w-h)/2; 69 | box[3]+=(w-h+1)/2; 70 | }else{ 71 | box[0]-=(h-w)/2; 72 | box[2]+=(h-w+1)/2; 73 | } 74 | } 75 | //防止边界溢出,并维持square大小 76 | public void limit_square(int w,int h){ 77 | if (box[0]<0 || box[1]<0){ 78 | int len=max(-box[0],-box[1]); 79 | box[0]+=len; 80 | box[1]+=len; 81 | } 82 | if (box[2]>=w || box[3]>=h){ 83 | int len=max(box[2]-w+1,box[3]-h+1); 84 | box[2]-=len; 85 | box[3]-=len; 86 | } 87 | } 88 | public void limit_square2(int w,int h){ 89 | if (width() > w) box[2]-=width()-w; 90 | if (height()> h) box[3]-=height()-h; 91 | if (box[0]<0){ 92 | int sz=-box[0]; 93 | box[0]+=sz; 94 | box[2]+=sz; 95 | } 96 | if (box[1]<0){ 97 | int sz=-box[1]; 98 | box[1]+=sz; 99 | box[3]+=sz; 100 | } 101 | if (box[2]>=w){ 102 | int sz=box[2]-w+1; 103 | box[2]-=sz; 104 | box[0]-=sz; 105 | } 106 | if (box[3]>=h){ 107 | int sz=box[3]-h+1; 108 | box[3]-=sz; 109 | box[1]-=sz; 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /app/src/main/java/com/cayden/face/facenet/FaceFeature.java: -------------------------------------------------------------------------------- 1 | package com.cayden.face.facenet; 2 | 3 | /** 4 | * Created by caydencui on 2018/9/6. 5 | * 人脸特征(512维特征值) 6 | * 相似度取特征向量之间的欧式距离. 7 | */ 8 | public class FaceFeature { 9 | public static final int DIMS=512; 10 | private float fea[]; 11 | public FaceFeature(){ 12 | fea=new float[DIMS]; 13 | } 14 | public float[] getFeature(){ 15 | return fea; 16 | } 17 | 18 | public void setFea(float[] fea) { 19 | this.fea = fea; 20 | } 21 | 22 | //比较当前特征和另一个特征之间的相似度 23 | public double compare(FaceFeature ff){ 24 | double dist=0; 25 | for (int i=0;i> 16) & 0xFF) - imageMean) / imageStd; 91 | floatValues[i * 3 + 1] = (((val >> 8) & 0xFF) - imageMean) / imageStd; 92 | floatValues[i * 3 + 2] = ((val & 0xFF) - imageMean) / imageStd; 93 | } 94 | //Log.d("Facenet","[*]normalizeImage"); 95 | //Log.d("Facenet","[*]normalizeImage"+intValues.length); 96 | return 0; 97 | } 98 | public FaceFeature recognizeImage(final Bitmap bitmap){ 99 | //Log.d("Facenet","[*]recognizeImage"); 100 | //(0)图片预处理,normailize 101 | normalizeImage(bitmap); 102 | //(1)Feed 103 | try { 104 | inferenceInterface.feed(INPUT_NAME, floatValues, 1, INPUT_SIZE, INPUT_SIZE, 3); 105 | boolean [] phase=new boolean[1]; 106 | // phase[0]=false; 107 | inferenceInterface.feed(PHASE_NAME,phase); 108 | 109 | }catch (Exception e){ 110 | Log.e("Facenet","[*] feed Error\n"+e); 111 | return null; 112 | } 113 | //(2)run 114 | // Log.d("Facenet","[*]Feed:"+INPUT_NAME); 115 | try { 116 | inferenceInterface.run(outputNames, false); 117 | }catch (Exception e){ 118 | Log.e("Facenet","[*] run error\n"+e); 119 | return null; 120 | } 121 | //(3)fetch 122 | FaceFeature faceFeature=new FaceFeature(); 123 | float[] outputs=faceFeature.getFeature(); 124 | try { 125 | inferenceInterface.fetch(OUTPUT_NAME, outputs); 126 | }catch (Exception e){ 127 | Log.e("Facenet","[*] fetch error\n"+e); 128 | return null; 129 | } 130 | return faceFeature; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /app/src/main/java/com/cayden/face/facenet/MTCNN.java: -------------------------------------------------------------------------------- 1 | package com.cayden.face.facenet; 2 | 3 | import android.content.res.AssetManager; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Matrix; 6 | import android.graphics.Point; 7 | import android.util.Log; 8 | 9 | 10 | import com.cayden.face.FaceApplication; 11 | 12 | import org.tensorflow.contrib.android.TensorFlowInferenceInterface; 13 | 14 | import java.util.Vector; 15 | 16 | import static java.lang.Math.max; 17 | import static java.lang.Math.min; 18 | 19 | /** 20 | * Created by caydencui on 2018/9/6. 21 | */ 22 | public class MTCNN { 23 | //参数 24 | private float factor=0.709f; 25 | private float PNetThreshold=0.6f; 26 | private float RNetThreshold=0.7f; 27 | private float ONetThreshold=0.7f; 28 | //MODEL PATH 29 | private static final String MODEL_FILE = "file:///android_asset/mtcnn_freezed_model.pb"; 30 | //tensor name 31 | private static final String PNetInName ="pnet/input:0"; 32 | private static final String[] PNetOutName =new String[]{"pnet/prob1:0","pnet/conv4-2/BiasAdd:0"}; 33 | private static final String RNetInName ="rnet/input:0"; 34 | private static final String[] RNetOutName =new String[]{ "rnet/prob1:0","rnet/conv5-2/conv5-2:0",}; 35 | private static final String ONetInName ="onet/input:0"; 36 | private static final String[] ONetOutName =new String[]{ "onet/prob1:0","onet/conv6-2/conv6-2:0","onet/conv6-3/conv6-3:0"}; 37 | 38 | 39 | private static class SingletonInstance { 40 | private static final MTCNN INSTANCE = new MTCNN(); 41 | } 42 | 43 | public static MTCNN getInstance() { 44 | return SingletonInstance.INSTANCE; 45 | } 46 | 47 | //安卓相关 48 | public long lastProcessTime; //最后一张图片处理的时间ms 49 | private static final String TAG="MTCNN"; 50 | private AssetManager assetManager; 51 | private TensorFlowInferenceInterface inferenceInterface; 52 | 53 | private MTCNN() { 54 | assetManager= FaceApplication.getMyApplication().getAssets(); 55 | loadModel(); 56 | } 57 | 58 | 59 | 60 | private boolean loadModel() { 61 | //AssetManager 62 | try { 63 | inferenceInterface = new TensorFlowInferenceInterface(assetManager, MODEL_FILE); 64 | Log.d("MTCNN","[*]load model success"); 65 | }catch(Exception e){ 66 | Log.e("MTCNN","[*]load model failed"+e); 67 | return false; 68 | } 69 | return true; 70 | } 71 | //读取Bitmap像素值,预处理(-127.5 /128),转化为一维数组返回 72 | private float[] normalizeImage(Bitmap bitmap){ 73 | int w=bitmap.getWidth(); 74 | int h=bitmap.getHeight(); 75 | float[] floatValues=new float[w*h*3]; 76 | int[] intValues=new int[w*h]; 77 | bitmap.getPixels(intValues,0,bitmap.getWidth(),0,0,bitmap.getWidth(),bitmap.getHeight()); 78 | float imageMean=127.5f; 79 | float imageStd=128; 80 | 81 | for (int i=0;i> 16) & 0xFF) - imageMean) / imageStd; 84 | floatValues[i * 3 + 1] = (((val >> 8) & 0xFF) - imageMean) / imageStd; 85 | floatValues[i * 3 + 2] = ((val & 0xFF) - imageMean) / imageStd; 86 | } 87 | return floatValues; 88 | } 89 | /* 90 | 检测人脸,minSize是最小的人脸像素值 91 | */ 92 | private Bitmap bitmapResize(Bitmap bm, float scale) { 93 | int width = bm.getWidth(); 94 | int height = bm.getHeight(); 95 | // CREATE A MATRIX FOR THE MANIPULATION。matrix指定图片仿射变换参数 96 | Matrix matrix = new Matrix(); 97 | // RESIZE THE BIT MAP 98 | matrix.postScale(scale, scale); 99 | Bitmap resizedBitmap = Bitmap.createBitmap( 100 | bm, 0, 0, width, height, matrix, true); 101 | return resizedBitmap; 102 | } 103 | //输入前要翻转,输出也要翻转 104 | private int PNetForward(Bitmap bitmap, float [][]PNetOutProb, float[][][]PNetOutBias){ 105 | int w=bitmap.getWidth(); 106 | int h=bitmap.getHeight(); 107 | 108 | float[] PNetIn=normalizeImage(bitmap); 109 | Utils.flip_diag(PNetIn,h,w,3); //沿着对角线翻转 110 | inferenceInterface.feed(PNetInName,PNetIn,1,w,h,3); 111 | inferenceInterface.run(PNetOutName,false); 112 | int PNetOutSizeW=(int) Math.ceil(w*0.5-5); 113 | int PNetOutSizeH=(int) Math.ceil(h*0.5-5); 114 | float[] PNetOutP=new float[PNetOutSizeW*PNetOutSizeH*2]; 115 | float[] PNetOutB=new float[PNetOutSizeW*PNetOutSizeH*4]; 116 | inferenceInterface.fetch(PNetOutName[0],PNetOutP); 117 | inferenceInterface.fetch(PNetOutName[1],PNetOutB); 118 | //【写法一】先翻转,后转为2/3维数组 119 | Utils.flip_diag(PNetOutP,PNetOutSizeW,PNetOutSizeH,2); 120 | Utils.flip_diag(PNetOutB,PNetOutSizeW,PNetOutSizeH,4); 121 | Utils.expand(PNetOutB,PNetOutBias); 122 | Utils.expandProb(PNetOutP,PNetOutProb); 123 | /* 124 | *【写法二】这个比较快,快了3ms。意义不大,用上面的方法比较直观 125 | for (int y=0;y boxes, float threshold, String method){ 138 | //NMS.两两比对 139 | //int delete_cnt=0; 140 | for(int i=0;i= threshold) { //删除prob小的那个框 159 | if (box.score>box2.score) 160 | box2.deleted=true; 161 | else 162 | box.deleted=true; 163 | //delete_cnt++; 164 | } 165 | } 166 | } 167 | } 168 | } 169 | //Log.i(TAG,"[*]sum:"+boxes.size()+" delete:"+delete_cnt); 170 | } 171 | private int generateBoxes(float[][] prob,float[][][]bias,float scale,float threshold,Vector boxes){ 172 | int h=prob.length; 173 | int w=prob[0].length; 174 | //Log.i(TAG,"[*]height:"+prob.length+" width:"+prob[0].length); 175 | for (int y=0;ythreadshold(0.6 here) 179 | if (score>PNetThreshold){ 180 | Box box=new Box(); 181 | //score 182 | box.score=score; 183 | //box 184 | box.box[0]= Math.round(x*2/scale); 185 | box.box[1]= Math.round(y*2/scale); 186 | box.box[2]= Math.round((x*2+11)/scale); 187 | box.box[3]= Math.round((y*2+11)/scale); 188 | //bbr 189 | for(int i=0;i<4;i++) 190 | box.bbr[i]=bias[y][x][i]; 191 | //add 192 | boxes.addElement(box); 193 | } 194 | } 195 | return 0; 196 | } 197 | private void BoundingBoxReggression(Vector boxes){ 198 | for (int i=0;i PNet(Bitmap bitmap, int minSize){ 209 | int whMin=min(bitmap.getWidth(),bitmap.getHeight()); 210 | float currentFaceSize=minSize; //currentFaceSize=minSize/(factor^k) k=0,1,2... until excced whMin 211 | Vector totalBoxes=new Vector(); 212 | //【1】Image Paramid and Feed to Pnet 213 | while (currentFaceSize<=whMin){ 214 | float scale=12.0f/currentFaceSize; 215 | //(1)Image Resize 216 | Bitmap bm=bitmapResize(bitmap,scale); 217 | int w=bm.getWidth(); 218 | int h=bm.getHeight(); 219 | //(2)RUN CNN 220 | int PNetOutSizeW=(int)(Math.ceil(w*0.5-5)+0.5); 221 | int PNetOutSizeH=(int)(Math.ceil(h*0.5-5)+0.5); 222 | float[][] PNetOutProb=new float[PNetOutSizeH][PNetOutSizeW];; 223 | float[][][] PNetOutBias=new float[PNetOutSizeH][PNetOutSizeW][4]; 224 | PNetForward(bm,PNetOutProb,PNetOutBias); 225 | //(3)数据解析 226 | Vector curBoxes=new Vector(); 227 | generateBoxes(PNetOutProb,PNetOutBias,scale,PNetThreshold,curBoxes); 228 | //Log.i(TAG,"[*]CNN Output Box number:"+curBoxes.size()+" Scale:"+scale); 229 | //(4)nms 0.5 230 | nms(curBoxes,0.5f,"Union"); 231 | //(5)add to totalBoxes 232 | for (int i=0;i> 16) & 0xFF) - imageMean) / imageStd; 260 | data[i * 3 + 1] = (((val >> 8) & 0xFF) - imageMean) / imageStd; 261 | data[i * 3 + 2] = ((val & 0xFF) - imageMean) / imageStd; 262 | } 263 | } 264 | /* 265 | * RNET跑神经网络,将score和bias写入boxes 266 | */ 267 | private void RNetForward(float[] RNetIn,Vector boxes){ 268 | int num=RNetIn.length/24/24/3; 269 | //feed & run 270 | inferenceInterface.feed(RNetInName,RNetIn,num,24,24,3); 271 | inferenceInterface.run(RNetOutName,false); 272 | //fetch 273 | float[] RNetP=new float[num*2]; 274 | float[] RNetB=new float[num*4]; 275 | inferenceInterface.fetch(RNetOutName[0],RNetP); 276 | inferenceInterface.fetch(RNetOutName[1],RNetB); 277 | //转换 278 | for (int i=0;i RNet(Bitmap bitmap, Vector boxes){ 286 | //RNet Input Init 287 | int num=boxes.size(); 288 | float[] RNetIn=new float[num*24*24*3]; 289 | float[] curCrop=new float[24*24*3]; 290 | int RNetInIdx=0; 291 | for (int i=0;i boxes){ 312 | int num=ONetIn.length/48/48/3; 313 | //feed & run 314 | inferenceInterface.feed(ONetInName,ONetIn,num,48,48,3); 315 | inferenceInterface.run(ONetOutName,false); 316 | //fetch 317 | float[] ONetP=new float[num*2]; //prob 318 | float[] ONetB=new float[num*4]; //bias 319 | float[] ONetL=new float[num*10]; //landmark 320 | inferenceInterface.fetch(ONetOutName[0],ONetP); 321 | inferenceInterface.fetch(ONetOutName[1],ONetB); 322 | inferenceInterface.fetch(ONetOutName[2],ONetL); 323 | //转换 324 | for (int i=0;i ONet(Bitmap bitmap, Vector boxes){ 342 | //ONet Input Init 343 | int num=boxes.size(); 344 | float[] ONetIn=new float[num*48*48*3]; 345 | float[] curCrop=new float[48*48*3]; 346 | int ONetInIdx=0; 347 | for (int i=0;i boxes, int w, int h){ 364 | //square 365 | for (int i=0;i detectFaces(Bitmap bitmap, int minFaceSize) { 378 | long t_start = System.currentTimeMillis(); 379 | //【1】PNet generate candidate boxes 380 | Vector boxes=PNet(bitmap,minFaceSize); 381 | square_limit(boxes,bitmap.getWidth(),bitmap.getHeight()); 382 | //【2】RNet 383 | boxes=RNet(bitmap,boxes); 384 | square_limit(boxes,bitmap.getWidth(),bitmap.getHeight()); 385 | //【3】ONet 386 | boxes=ONet(bitmap,boxes); 387 | //return 388 | Log.i(TAG,"[*]Mtcnn Detection Time:"+(System.currentTimeMillis()-t_start)); 389 | lastProcessTime=(System.currentTimeMillis()-t_start); 390 | return boxes; 391 | } 392 | } 393 | -------------------------------------------------------------------------------- /app/src/main/java/com/cayden/face/facenet/Utils.java: -------------------------------------------------------------------------------- 1 | package com.cayden.face.facenet; 2 | import android.graphics.Bitmap; 3 | import android.graphics.Canvas; 4 | import android.graphics.Color; 5 | import android.graphics.Matrix; 6 | import android.graphics.Paint; 7 | import android.graphics.Point; 8 | import android.graphics.Rect; 9 | import android.util.Log; 10 | 11 | import java.util.Vector; 12 | 13 | import static java.lang.Math.max; 14 | import static java.lang.Math.min; 15 | 16 | /** 17 | * Created by caydencui on 2018/9/6. 18 | */ 19 | public class Utils { 20 | //复制图片,并设置isMutable=true 21 | public static Bitmap copyBitmap(Bitmap bitmap){ 22 | return bitmap.copy(bitmap.getConfig(),true); 23 | } 24 | //在bitmap中画矩形 25 | public static void drawRect(Bitmap bitmap, Rect rect, int thick){ 26 | try { 27 | Canvas canvas = new Canvas(bitmap); 28 | Paint paint = new Paint(); 29 | int r=255;//(int)(Math.random()*255); 30 | int g=0;//(int)(Math.random()*255); 31 | int b=0;//(int)(Math.random()*255); 32 | paint.setColor(Color.rgb(r, g, b)); 33 | paint.setStrokeWidth(thick); 34 | paint.setStyle(Paint.Style.STROKE); 35 | canvas.drawRect(rect, paint); 36 | //Log.i("Util","[*]draw rect"); 37 | }catch (Exception e){ 38 | Log.i("Utils","[*] error"+e); 39 | // e.printStackTrace(); 40 | } 41 | } 42 | //在图中画点 43 | public static void drawPoints(Bitmap bitmap, Point[] landmark, int thick){ 44 | for (int i=0;i boxes){ 91 | int cnt=0; 92 | for (int i=0;i updateBoxes(Vector boxes){ 102 | Vector b=new Vector(); 103 | for (int i=0;i>16)&0xff)+"G:"+((v>>8)&0xff)+ " B:"+(v&0xff)); 123 | } 124 | static public Bitmap resize(Bitmap _bitmap, int new_width){ 125 | float scale=((float)new_width)/_bitmap.getWidth(); 126 | Matrix matrix=new Matrix(); 127 | matrix.postScale(scale,scale); 128 | Bitmap bitmap= Bitmap.createBitmap(_bitmap,0,0,_bitmap.getWidth(),_bitmap.getHeight(),matrix,true); 129 | return bitmap; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /app/src/main/java/com/cayden/face/stream/ExtByteTools.java: -------------------------------------------------------------------------------- 1 | package com.cayden.face.stream; 2 | 3 | /** 4 | * Created by caydencui on 2018/9/6. 5 | */ 6 | 7 | public class ExtByteTools { 8 | 9 | public static byte[] convert_from_int(int val) { 10 | byte[] size = new byte[4]; 11 | size[0] = (byte)(val >> 24); 12 | size[1] = (byte)(val >> 16); 13 | size[2] = (byte)(val >> 8); 14 | size[3] = (byte)(val >> 0); 15 | return size; 16 | } 17 | public static int convert_to_int(byte[] val) { 18 | int size = 0; 19 | if (val.length >= 4) { 20 | size |= ((val[0] & 0xFF) << 24); 21 | size |= ((val[1] & 0xFF) << 16); 22 | size |= ((val[2] & 0xFF) << 8); 23 | size |= ((val[3] & 0xFF) << 0); 24 | } 25 | return size; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/cayden/face/stream/ExtInputStream.java: -------------------------------------------------------------------------------- 1 | package com.cayden.face.stream; 2 | 3 | import java.io.BufferedInputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | 7 | /** 8 | * Created by caydencui on 2018/9/6. 9 | */ 10 | 11 | public class ExtInputStream extends BufferedInputStream { 12 | public ExtInputStream(InputStream in) { 13 | super(in); 14 | } 15 | 16 | public ExtInputStream(InputStream in, int size) { 17 | super(in, size); 18 | } 19 | 20 | public String readString() throws IOException { 21 | byte[] size = new byte[4]; 22 | if (read(size) > 0) { 23 | byte[] name = new byte[ExtByteTools.convert_to_int(size)]; 24 | if (name.length == read(name)) { 25 | return new String(name); 26 | } 27 | } 28 | return null; 29 | } 30 | 31 | public byte[] readBytes() throws IOException { 32 | byte[] size = new byte[4]; 33 | if (read(size) > 0) { 34 | byte[] data = new byte[ExtByteTools.convert_to_int(size)]; 35 | if (data.length == read(data)) { 36 | return data; 37 | } 38 | } 39 | return null; 40 | } 41 | 42 | public boolean readBytes(byte[] data) throws IOException { 43 | byte[] size = new byte[4]; 44 | if (read(size) > 0) { 45 | if (ExtByteTools.convert_to_int(size) == data.length) { 46 | if (data.length == read(data)) { 47 | return true; 48 | } 49 | } 50 | } 51 | return false; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/cayden/face/stream/ExtOutputStream.java: -------------------------------------------------------------------------------- 1 | package com.cayden.face.stream; 2 | 3 | import java.io.BufferedOutputStream; 4 | import java.io.IOException; 5 | import java.io.OutputStream; 6 | 7 | /** 8 | * Created by caydencui on 2018/9/6. 9 | */ 10 | 11 | public class ExtOutputStream extends BufferedOutputStream { 12 | public ExtOutputStream(OutputStream out) { 13 | super(out); 14 | } 15 | 16 | public ExtOutputStream(OutputStream out, int size) { 17 | super(out, size); 18 | } 19 | 20 | public boolean writeString(String name) throws IOException { 21 | write(ExtByteTools.convert_from_int(name.getBytes().length)); 22 | write(name.getBytes()); 23 | return true; 24 | } 25 | 26 | public boolean writeBytes(byte[] data) throws IOException { 27 | write(ExtByteTools.convert_from_int(data.length)); 28 | write(data); 29 | return false; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/cayden/face/utils/ImageUtils.java: -------------------------------------------------------------------------------- 1 | package com.cayden.face.utils; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.graphics.Bitmap; 6 | import android.net.Uri; 7 | import android.os.Environment; 8 | import android.util.Log; 9 | import android.widget.Toast; 10 | 11 | import java.io.File; 12 | import java.io.FileNotFoundException; 13 | import java.io.FileOutputStream; 14 | import java.io.IOException; 15 | import java.text.SimpleDateFormat; 16 | import java.util.Date; 17 | 18 | /** 19 | * Created by caydencui on 2018/9/10. 20 | */ 21 | 22 | public class ImageUtils { 23 | 24 | public static final int MEDIA_TYPE_IMAGE = 1; 25 | public static final int MEDIA_TYPE_VIDEO = 2; 26 | 27 | // save image to sdcard path: Pictures/MyTestImage/ 28 | public static void saveImageData(byte[] imageData) { 29 | File imageFile = getOutputMediaFile(MEDIA_TYPE_IMAGE); 30 | if (imageFile == null) return; 31 | try { 32 | FileOutputStream fos = new FileOutputStream(imageFile); 33 | fos.write(imageData); 34 | fos.close(); 35 | Log.d("save","saved in "+imageFile.getAbsolutePath()); 36 | } catch (FileNotFoundException e) { 37 | e.printStackTrace(); 38 | } catch (IOException e) { 39 | e.printStackTrace(); 40 | } 41 | } 42 | 43 | public static File getOutputMediaFile(int type) { 44 | File imageFileDir = 45 | new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyTestImage"); 46 | if (!imageFileDir.exists()) if (!imageFileDir.mkdirs()) { 47 | return null; 48 | } 49 | // Create a media file name 50 | String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); 51 | File imageFile; 52 | if (type == MEDIA_TYPE_IMAGE) { 53 | imageFile = new File(imageFileDir.getPath() + File.separator + 54 | "IMG_" + timeStamp + ".jpg"); 55 | } else if (type == MEDIA_TYPE_VIDEO) { 56 | imageFile = new File(imageFileDir.getPath() + File.separator + 57 | "VID_" + timeStamp + ".mp4"); 58 | } else return null; 59 | return imageFile; 60 | } 61 | 62 | /** 63 | * save bitmap to image 64 | * @param bitmap 65 | * @return 66 | */ 67 | public static boolean saveImg(Bitmap bitmap) { 68 | try { 69 | String sdcardPath = System.getenv("EXTERNAL_STORAGE"); //获得sd卡路径 70 | String dir = sdcardPath + "/facesample/"; //图片保存的文件夹名 71 | File file = new File(dir); //已File来构建 72 | if (!file.exists()) { //如果不存在 就mkdirs()创建此文件夹 73 | file.mkdirs(); 74 | } 75 | Log.i("SaveImg", "file uri==>" + dir); 76 | // Create a media file name 77 | String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); 78 | File mFile = new File(dir + timeStamp+".jpg"); //将要保存的图片文件 79 | 80 | FileOutputStream outputStream = new FileOutputStream(mFile); //构建输出流 81 | bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream); //compress到输出outputStream 82 | 83 | return true; 84 | 85 | } catch (FileNotFoundException e) { 86 | e.printStackTrace(); 87 | } 88 | return false; 89 | } 90 | 91 | 92 | } 93 | 94 | 95 | -------------------------------------------------------------------------------- /app/src/main/java/com/cayden/face/utils/NV21ToBitmap.java: -------------------------------------------------------------------------------- 1 | package com.cayden.face.utils; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.renderscript.Allocation; 6 | import android.renderscript.Element; 7 | import android.renderscript.RenderScript; 8 | import android.renderscript.ScriptIntrinsicYuvToRGB; 9 | import android.renderscript.Type; 10 | 11 | /** 12 | * Created by caydencui on 2018/12/7. 13 | */ 14 | 15 | public class NV21ToBitmap { 16 | 17 | private RenderScript rs; 18 | private ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic; 19 | private Type.Builder yuvType, rgbaType; 20 | private Allocation in, out; 21 | 22 | public NV21ToBitmap(Context context) { 23 | rs = RenderScript.create(context); 24 | yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs)); 25 | } 26 | 27 | public Bitmap nv21ToBitmap(byte[] nv21, int width, int height){ 28 | if (yuvType == null){ 29 | yuvType = new Type.Builder(rs, Element.U8(rs)).setX(nv21.length); 30 | in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT); 31 | 32 | rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(width).setY(height); 33 | out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT); 34 | } 35 | 36 | in.copyFrom(nv21); 37 | 38 | yuvToRgbIntrinsic.setInput(in); 39 | yuvToRgbIntrinsic.forEach(out); 40 | 41 | Bitmap bmpout = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 42 | out.copyTo(bmpout); 43 | 44 | return bmpout; 45 | 46 | } 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/cayden/face/vlc/AppBeanService.java: -------------------------------------------------------------------------------- 1 | package com.cayden.face.vlc; 2 | 3 | import android.util.Log; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import momo.cn.edu.fjnu.androidutils.base.BaseBeanService; 9 | 10 | public abstract class AppBeanService implements BaseBeanService { 11 | private final String TAG = AppBeanService.class.getSimpleName(); 12 | @Override 13 | public void save(T object) { 14 | try { 15 | UdpPlayerApplication.mDBManager.save(object); 16 | } catch (Exception e) { 17 | e.printStackTrace(); 18 | } 19 | } 20 | 21 | @Override 22 | public void delete(T object) { 23 | try { 24 | UdpPlayerApplication.mDBManager.delete(object); 25 | } catch (Exception e) { 26 | e.printStackTrace(); 27 | } 28 | } 29 | 30 | @Override 31 | public void update(T object) { 32 | try { 33 | UdpPlayerApplication.mDBManager.update(object); 34 | } catch (Exception e) { 35 | e.printStackTrace(); 36 | } 37 | } 38 | 39 | @Override 40 | public List getAll(Class tClass) { 41 | List lists = new ArrayList(); 42 | try { 43 | lists = UdpPlayerApplication.mDBManager.findAll(tClass); 44 | } catch (Exception e) { 45 | e.printStackTrace(); 46 | } 47 | return lists; 48 | } 49 | 50 | @Override 51 | public T getObjectById(Class tClass, Object id) { 52 | T object = null; 53 | try { 54 | object = UdpPlayerApplication.mDBManager.findById(tClass, id); 55 | } catch (Exception e) { 56 | e.printStackTrace(); 57 | } 58 | return object; 59 | } 60 | 61 | @Override 62 | public abstract boolean isExist(T object) ; 63 | 64 | @Override 65 | public void saveAll(List objects) { 66 | try { 67 | UdpPlayerApplication.mDBManager.save(objects); 68 | 69 | } catch (Exception e) { 70 | Log.e(TAG, "saveAll->exception:" + e); 71 | e.printStackTrace(); 72 | } 73 | 74 | } 75 | 76 | @Override 77 | public void updateAll(List objects) { 78 | try { 79 | UdpPlayerApplication.mDBManager.update(objects); 80 | } catch (Exception e) { 81 | e.printStackTrace(); 82 | } 83 | } 84 | 85 | @Override 86 | public void saveOrUpdateAll(List objects) { 87 | try { 88 | UdpPlayerApplication.mDBManager.saveOrUpdate(objects); 89 | } catch (Exception e) { 90 | Log.e(TAG, "saveOrUpdateAll->exception:" + e); 91 | e.printStackTrace(); 92 | } 93 | } 94 | 95 | public void saveOrUpdate(T object){ 96 | try { 97 | UdpPlayerApplication.mDBManager.saveOrUpdate(object); 98 | } catch (Exception e) { 99 | e.printStackTrace(); 100 | } 101 | } 102 | } -------------------------------------------------------------------------------- /app/src/main/java/com/cayden/face/vlc/ConstData.java: -------------------------------------------------------------------------------- 1 | package com.cayden.face.vlc; 2 | 3 | 4 | import momo.cn.edu.fjnu.androidutils.data.CommonValues; 5 | 6 | public class ConstData { 7 | public static final int DB_VERSION = 1; 8 | public static final String DB_DIRECTORY = CommonValues.application.getFilesDir().getPath(); 9 | public static final String DB_NAME = "udp_player.db"; 10 | 11 | public static final int DEFAULT_PREVIEW_WIDTH = 800; 12 | public static final int DEFAULT_PREVIEW_HEIGHT = 654; 13 | public static final int PIXEL_SIZE = 4; 14 | public static final int DEFAULT_PREVIEW_MODE = 0; 15 | public static final int DEFAULT_PREVIEW_MIN_FPS = 1; 16 | public static final int DEFAULT_PREVIEW_MAX_FPS = 30; 17 | public static final float DEFAULT_BANDWIDTH = 1.0f; 18 | 19 | public static final int FRAME_FORMAT_YUYV = 0; 20 | public static final int FRAME_FORMAT_MJPEG = 1; 21 | 22 | public static final int PIXEL_FORMAT_RAW = 0; 23 | public static final int PIXEL_FORMAT_YUV = 1; 24 | public static final int PIXEL_FORMAT_RGB565 = 2; 25 | public static final int PIXEL_FORMAT_RGBX = 3; 26 | public static final int PIXEL_FORMAT_YUV420SP = 4; 27 | public static final int PIXEL_FORMAT_NV21 = 5; // = YVU420SemiPlanar 28 | 29 | public interface IntentKey{ 30 | String VIDEO_URL = "video_url"; 31 | String INSTALL_TIME = "install_time"; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/cayden/face/vlc/Rtsp.java: -------------------------------------------------------------------------------- 1 | package com.cayden.face.vlc; 2 | 3 | import android.content.Context; 4 | import android.media.MediaCodec; 5 | import android.media.MediaFormat; 6 | import android.net.Uri; 7 | import android.os.Process; 8 | import android.util.Log; 9 | import android.view.SurfaceView; 10 | import android.view.TextureView; 11 | 12 | import org.videolan.libvlc.IVLCVout; 13 | import org.videolan.libvlc.LibVLC; 14 | import org.videolan.libvlc.Media; 15 | import org.videolan.libvlc.MediaPlayCallback; 16 | import org.videolan.libvlc.MediaPlayer; 17 | 18 | import java.io.File; 19 | import java.io.FileOutputStream; 20 | import java.io.IOException; 21 | import java.nio.ByteBuffer; 22 | import java.util.ArrayList; 23 | 24 | 25 | public class Rtsp { 26 | 27 | private String mUrl; 28 | private MediaPlayer mMediaPlayer = null; 29 | private LibVLC mLibVLC = null; 30 | private Context mContext; 31 | private SurfaceView msView = null; 32 | private TextureView mtView = null; 33 | private Thread mGetFrameBufferThread; 34 | private RtspCallbackInterface mNxpRtspCallbackInterface=null; 35 | private String TAG ="Rtsp"; 36 | private MediaCodec mMediaCodec = null; 37 | private MediaFormat mOutFormat; 38 | private SurfaceView mSurfaceView = null; 39 | private int mRotationDegrees = 0; 40 | private int mLostFrameCount = 0; 41 | private int mRenderMode = 1; 42 | private int mcxVideo = 0; 43 | private int mcyVideo = 0; 44 | private int mNxpRtspState=-1; 45 | public int len=10; 46 | public byte[] frameData = new byte[4000000]; 47 | public int[] frameInfo = new int[2]; 48 | 49 | 50 | public Rtsp(Context context, RtspCallbackInterface callback){ 51 | mContext=context; 52 | mNxpRtspCallbackInterface=callback; 53 | } 54 | public boolean SetUrl(String url){ 55 | this.mUrl=url; 56 | return true; 57 | } 58 | 59 | public boolean init(SurfaceView sView, SurfaceView tView){ 60 | 61 | final ArrayList args = new ArrayList<>(); 62 | args.add("-vvv"); 63 | mLibVLC = new LibVLC(mContext, args); 64 | mMediaPlayer = new MediaPlayer(mLibVLC); 65 | 66 | //init mMediaPlayer 67 | final IVLCVout vlcVout = mMediaPlayer.getVLCVout(); 68 | if(sView!=null) { 69 | msView = sView; 70 | vlcVout.setVideoView(mtView); 71 | } 72 | else if(tView!=null){ 73 | mSurfaceView=tView; 74 | vlcVout.setVideoView(mSurfaceView); 75 | 76 | } 77 | 78 | vlcVout.attachViews(); 79 | 80 | Media media = new Media(mLibVLC, Uri.parse(mUrl)); 81 | media.setHWDecoderEnabled(true,true); 82 | media.addOption(":no-audio"); 83 | media.addOption(":network-caching=150"); 84 | media.addOption(":file-caching=150"); 85 | media.addOption(":sout-mux-caching=150"); 86 | media.addOption(":live-caching=150"); 87 | mMediaPlayer.setMedia(media); 88 | // 89 | mMediaPlayer.getVLCVout().setWindowSize(ConstData.DEFAULT_PREVIEW_WIDTH,ConstData.DEFAULT_PREVIEW_HEIGHT); 90 | mMediaPlayer.setAspectRatio(ConstData.DEFAULT_PREVIEW_WIDTH+":"+ConstData.DEFAULT_PREVIEW_HEIGHT); 91 | mMediaPlayer.setScale(0); 92 | 93 | media.release(); 94 | float scale=704/576; 95 | // vlcVout.setWindowSize(1280,(int)(1280/scale)); 96 | // vlcVout.setWindowSize(1280,720); 97 | //creat a thread to get the frame data 98 | this.mGetFrameBufferThread=new Thread(this.mGetFrameBufferRun); 99 | 100 | 101 | return true; 102 | } 103 | 104 | public boolean init(SurfaceView sView, TextureView tView){ 105 | 106 | final ArrayList args = new ArrayList<>(); 107 | args.add("-vvv"); 108 | mLibVLC = new LibVLC(mContext, args); 109 | mMediaPlayer = new MediaPlayer(mLibVLC); 110 | 111 | //init mMediaPlayer 112 | final IVLCVout vlcVout = mMediaPlayer.getVLCVout(); 113 | if(sView!=null) { 114 | msView = sView; 115 | vlcVout.setVideoView(mtView); 116 | } 117 | else if(tView!=null){ 118 | mtView=tView; 119 | vlcVout.setVideoView(mtView); 120 | } 121 | 122 | vlcVout.attachViews(); 123 | 124 | Media media = new Media(mLibVLC, Uri.parse(mUrl)); 125 | media.setHWDecoderEnabled(true,true); 126 | media.addOption(":no-audio"); 127 | media.addOption(":network-caching=150"); 128 | media.addOption(":file-caching=150"); 129 | media.addOption(":sout-mux-caching=150"); 130 | media.addOption(":live-caching=150"); 131 | mMediaPlayer.setMedia(media); 132 | 133 | mMediaPlayer.getVLCVout().setWindowSize(ConstData.DEFAULT_PREVIEW_WIDTH,ConstData.DEFAULT_PREVIEW_HEIGHT); 134 | mMediaPlayer.setAspectRatio(ConstData.DEFAULT_PREVIEW_WIDTH+":"+ConstData.DEFAULT_PREVIEW_HEIGHT); 135 | mMediaPlayer.setScale(0); 136 | 137 | media.release(); 138 | 139 | //creat a thread to get the frame data 140 | this.mGetFrameBufferThread=new Thread(this.mGetFrameBufferRun); 141 | 142 | 143 | return true; 144 | } 145 | 146 | public void setVideoCallback(MediaPlayCallback mediaPlayCallback){ 147 | if(mMediaPlayer!=null){ 148 | ByteBuffer frameBuffer = ByteBuffer.allocateDirect(ConstData.DEFAULT_PREVIEW_WIDTH*ConstData.DEFAULT_PREVIEW_HEIGHT*ConstData.PIXEL_SIZE); 149 | mMediaPlayer.setVideoFormat("RGBA",ConstData.DEFAULT_PREVIEW_WIDTH,ConstData.DEFAULT_PREVIEW_HEIGHT,ConstData.PIXEL_SIZE); 150 | mMediaPlayer.setVideoCallback(frameBuffer,mediaPlayCallback); 151 | } 152 | } 153 | 154 | public boolean play(){ 155 | Process.setThreadPriority(-20); 156 | mMediaPlayer.play(); 157 | //test(); 158 | this.mGetFrameBufferThread.start(); 159 | 160 | 161 | return true; 162 | } 163 | void sleep(int millisecond) 164 | { 165 | try 166 | { 167 | Thread.sleep(millisecond); 168 | } 169 | catch (InterruptedException e) 170 | { 171 | e.printStackTrace(); 172 | } 173 | } 174 | 175 | private void test() throws IOException { 176 | // byte[] array = {9,100,10,37,5,10}; 177 | 178 | len=mMediaPlayer.getBuffer(frameData,frameInfo); 179 | /// for(int temp=0;temp<10;temp++){ 180 | /// Log.d(TAG, "the Array len is "+frameData[temp]); 181 | /// } 182 | //确定写出文件的位置 183 | File file = new File("/sdcard/DumpData.yuv"); 184 | FileOutputStream fos = new FileOutputStream(file); 185 | fos.write(frameData); 186 | fos.close(); 187 | Log.d(TAG, "the Array len is "+len); 188 | } 189 | 190 | public boolean stop(){ 191 | mMediaPlayer.stop(); 192 | this.mGetFrameBufferThread.interrupt(); 193 | mMediaPlayer.getVLCVout().detachViews(); 194 | return true; 195 | } 196 | public boolean pause(){ 197 | mMediaPlayer.pause(); 198 | mMediaPlayer.getVLCVout().detachViews(); 199 | return true; 200 | } 201 | 202 | public static boolean mRun=true; 203 | 204 | 205 | private Runnable mGetFrameBufferRun=new Runnable() { 206 | @Override 207 | public void run() 208 | { 209 | // Process.setThreadPriority(-8); 210 | 211 | while(true) { 212 | 213 | try { 214 | if(mRun) { 215 | // sleep(100); 216 | len = mMediaPlayer.getBuffer(frameData, frameInfo); 217 | if(len>0){ 218 | mNxpRtspCallbackInterface.decodeOutputBuffer(len,frameData,frameInfo[0],frameInfo[1]); 219 | } 220 | // LocalFaceSDK.getInstance(null).cwPushBinaryFrame(frameData, frameInfo[0], frameInfo[1], 221 | // FaceInterface.cw_img_form_t.CW_IMAGE_NV12, CaremaType.BACK_LANDSCAPE); 222 | } 223 | // test(); 224 | } catch (Exception e) { 225 | e.printStackTrace(); 226 | } 227 | } 228 | } 229 | }; 230 | } 231 | -------------------------------------------------------------------------------- /app/src/main/java/com/cayden/face/vlc/RtspCallbackInterface.java: -------------------------------------------------------------------------------- 1 | package com.cayden.face.vlc; 2 | 3 | public abstract interface RtspCallbackInterface { 4 | public abstract void decodeOutputBuffer(int frameLen, byte[] frameBuffer, long width, long height); 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/java/com/cayden/face/vlc/UdpPlayerApplication.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.cayden.face.vlc; 5 | 6 | import org.xutils.DbManager; 7 | import org.xutils.x; 8 | 9 | import java.io.File; 10 | 11 | import momo.cn.edu.fjnu.androidutils.base.BaseApplication; 12 | 13 | public class UdpPlayerApplication extends BaseApplication { 14 | public static DbManager mDBManager; 15 | 16 | @Override 17 | public void onCreate() { 18 | super.onCreate(); 19 | DbManager.DaoConfig dbConfig = new DbManager.DaoConfig().setDbDir(new File(ConstData.DB_DIRECTORY)) 20 | .setDbName(ConstData.DB_NAME).setDbVersion(ConstData.DB_VERSION).setAllowTransaction(true) 21 | .setDbOpenListener(new DbManager.DbOpenListener() { 22 | @Override 23 | public void onDbOpened(DbManager db) { 24 | db.getDatabase().enableWriteAheadLogging(); 25 | } 26 | }).setDbUpgradeListener(null); 27 | if (null == mDBManager) 28 | mDBManager = x.getDb(dbConfig); 29 | mDBManager = x.getDb(dbConfig); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/cayden/face/vlc/UrlInfo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.cayden.face.vlc; 5 | 6 | import org.xutils.db.annotation.Column; 7 | import org.xutils.db.annotation.Table; 8 | 9 | @Table(name="UrlInfo") 10 | public class UrlInfo { 11 | @Column(name="id", isId=true, autoGen=true) 12 | private int id; 13 | @Column(name="url", property="UNIQUE") 14 | private String url; 15 | public int getId() { 16 | return id; 17 | } 18 | public void setId(int id) { 19 | this.id = id; 20 | } 21 | public String getUrl() { 22 | return url; 23 | } 24 | public void setUrl(String url) { 25 | this.url = url; 26 | } 27 | @Override 28 | public String toString() { 29 | return url; 30 | } 31 | 32 | @Override 33 | protected void finalize() throws Throwable { 34 | super.finalize(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/cayden/face/vlc/UrlInfoService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.cayden.face.vlc; 5 | 6 | import org.xutils.ex.DbException; 7 | 8 | import java.util.List; 9 | 10 | 11 | public class UrlInfoService extends AppBeanService{ 12 | 13 | @Override 14 | public boolean isExist(UrlInfo object) { 15 | return false; 16 | } 17 | 18 | public List getAll(){ 19 | return getAll(UrlInfo.class); 20 | } 21 | 22 | public void deleteAll(){ 23 | try { 24 | UdpPlayerApplication.mDBManager.delete(UrlInfo.class); 25 | } catch (DbException e) { 26 | e.printStackTrace(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /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_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/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_register.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 14 | 21 | 22 | 28 | 29 |