├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── markdown-navigator.xml ├── markdown-navigator │ └── profiles_settings.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── 1.gif ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── jerei │ │ └── videodemo │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── jerei │ │ │ └── videodemo │ │ │ ├── MainActivity.java │ │ │ └── SystemAppUtils.java │ └── res │ │ ├── drawable │ │ ├── btn_video.png │ │ ├── btn_video_hover.png │ │ ├── btn_video_record.xml │ │ └── style_recorder_progress.xml │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── example │ └── jerei │ └── videodemo │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── shvideolibrary ├── .gitignore ├── assets ├── armeabi-v7a-neon │ └── ffmpeg ├── armeabi-v7a │ └── ffmpeg └── x86 │ └── ffmpeg ├── build.gradle ├── libs ├── armeabi-v7a │ └── libARM_ARCH.so ├── armeabi │ └── libARM_ARCH.so ├── sardar.jar └── x86 │ └── libARM_ARCH.so ├── proguard-rules.pro └── src ├── androidTest └── java │ └── com │ └── sh │ └── shvideolibrary │ └── ExampleInstrumentedTest.java ├── main ├── AndroidManifest.xml ├── java │ └── com │ │ └── sh │ │ └── shvideolibrary │ │ ├── CameraPreview.java │ │ ├── VideoInputActivity.java │ │ ├── VideoInputDialog.java │ │ └── compression │ │ ├── CompressListener.java │ │ ├── Compressor.java │ │ ├── CompressorUtils.java │ │ └── InitListener.java └── res │ ├── drawable │ ├── btn_video.png │ ├── btn_video_hover.png │ ├── btn_video_record.xml │ └── style_recorder_progress.xml │ ├── layout │ ├── activity_video_input.xml │ └── dialog_video_input.xml │ ├── mipmap-xxxhdpi │ ├── ic_camera_menu_switch.png │ ├── ic_flash_off_white.png │ ├── ic_flash_on_white.png │ ├── ic_launcher.png │ ├── player_record.png │ └── player_stop.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml └── test └── java └── com └── sh └── shvideolibrary └── ExampleUnitTest.java /.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/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/markdown-navigator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 32 | 33 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /.idea/markdown-navigator/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 49 | 50 | 51 | 52 | 53 | Android API 7 Platform 54 | 55 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hui46226021/ShVideoDemo/65aa06fcf153371d2e36e2589110fdd7519baba4/1.gif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ShVideoDemo 2 | Android 视频录制Demo 防微信小视频 视频压缩(FFmpeg) 3 | 4 | #Download 5 | 6 | Download the latest JAR or grab via Maven: 7 | ~~~xml 8 | 9 | com.sh.shvideo 10 | shvideolibrary 11 | 1.5.0 12 | pom 13 | 14 | ~~~ 15 | or Gradle: 16 | ~~~gradle 17 | compile 'com.sh.shvideo:shvideolibrary:1.5.0' 18 | ~~~ 19 | 注意:targetSdkVersion 23 及以上 要注意 6.0运行时权限 或干脆用23以下 20 | 21 | ![](1.gif) -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion "25.0.0" 6 | defaultConfig { 7 | applicationId "com.sh.zsh.code" 8 | minSdkVersion 15 9 | targetSdkVersion 22 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 | 23 | dependencies { 24 | compile fileTree(include: ['*.jar'], dir: 'libs') 25 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 26 | exclude group: 'com.android.support', module: 'support-annotations' 27 | }) 28 | compile 'com.android.support:appcompat-v7:24.2.1' 29 | testCompile 'junit:junit:4.12' 30 | compile project(path: ':shvideolibrary') 31 | } 32 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Java\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/jerei/videodemo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.example.jerei.videodemo; 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 | * Instrumentation 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.example.jerei.videodemo", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/jerei/videodemo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.jerei.videodemo; 2 | 3 | import android.Manifest; 4 | import android.app.Activity; 5 | import android.content.Intent; 6 | import android.content.pm.ActivityInfo; 7 | import android.content.pm.PackageManager; 8 | import android.graphics.Bitmap; 9 | import android.graphics.PixelFormat; 10 | import android.media.MediaMetadataRetriever; 11 | import android.media.MediaRecorder; 12 | import android.media.ThumbnailUtils; 13 | import android.os.Build; 14 | import android.provider.MediaStore; 15 | import android.support.v4.app.FragmentActivity; 16 | import android.support.v7.app.AppCompatActivity; 17 | import android.os.Bundle; 18 | import android.text.TextUtils; 19 | import android.util.Log; 20 | import android.view.SurfaceHolder; 21 | import android.view.SurfaceView; 22 | import android.view.View; 23 | import android.view.Window; 24 | import android.view.WindowManager; 25 | import android.widget.Button; 26 | import android.widget.ImageView; 27 | import android.widget.ProgressBar; 28 | import android.widget.ScrollView; 29 | import android.widget.TextView; 30 | import android.widget.Toast; 31 | 32 | 33 | import com.sh.shvideolibrary.VideoInputActivity; 34 | import com.sh.shvideolibrary.VideoInputDialog; 35 | import com.sh.shvideolibrary.compression.CompressListener; 36 | import com.sh.shvideolibrary.compression.CompressorUtils; 37 | 38 | import java.io.File; 39 | import java.io.IOException; 40 | import java.util.ArrayList; 41 | import java.util.List; 42 | import java.util.regex.Matcher; 43 | import java.util.regex.Pattern; 44 | 45 | /** 46 | * Created by zhush on 2016/11/11 47 | * E-mail zhush@jerei.com 48 | * PS 視頻DEMO 49 | */ 50 | public class MainActivity extends AppCompatActivity implements VideoInputDialog.VideoCall{ 51 | 52 | ImageView image; 53 | ImageView imag2; 54 | Button button; 55 | Button button2; 56 | Button button3; 57 | 58 | TextView first; 59 | TextView back; 60 | ProgressBar progressBar; 61 | 62 | 63 | static String TAG="MainActivity"; 64 | 65 | String path;//视频录制输出地址 66 | //视频压缩数据地址 67 | private String currentOutputVideoPath = "/mnt/sdcard/out.mp4"; 68 | private static final int REQUEST_CODE_FOR_RECORD_VIDEO = 5230;//录制视频请求码 69 | Double videoLength=0.0;//视频时长 70 | @Override 71 | protected void onCreate(Bundle savedInstanceState) { 72 | super.onCreate(savedInstanceState); 73 | setContentView(R.layout.activity_main); 74 | image = (ImageView) findViewById(R.id.image); 75 | button = (Button) findViewById(R.id.button); 76 | button2 = (Button) findViewById(R.id.button2); 77 | button3 = (Button) findViewById(R.id.button3); 78 | first = (TextView) findViewById(R.id.first); 79 | back = (TextView) findViewById(R.id.back); 80 | progressBar= (ProgressBar) findViewById(R.id.progressBar); 81 | imag2 = (ImageView) findViewById(R.id.imag2); 82 | button.setOnClickListener(new View.OnClickListener() { 83 | @Override 84 | public void onClick(View view) { 85 | //显示视频录制控件 86 | VideoInputDialog.show(getSupportFragmentManager(),MainActivity.this,VideoInputDialog.Q720,MainActivity.this); 87 | } 88 | }); 89 | button2.setOnClickListener(new View.OnClickListener() { 90 | @Override 91 | public void onClick(View view) { 92 | VideoInputActivity.startActivityForResult(MainActivity.this, REQUEST_CODE_FOR_RECORD_VIDEO,VideoInputActivity.Q720); 93 | } 94 | }); 95 | /** 96 | * 压缩视频 97 | */ 98 | button3.setOnClickListener(new View.OnClickListener() { 99 | @Override 100 | public void onClick(View view) { 101 | //获取视频时长 计算压缩进度用 102 | MediaMetadataRetriever retr = new MediaMetadataRetriever(); 103 | retr.setDataSource(path); 104 | String time = retr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);//获取视频时长 105 | //7680 106 | try { 107 | videoLength = Double.parseDouble(time)/1000.00; 108 | } catch (Exception e) { 109 | e.printStackTrace(); 110 | videoLength = 0.00; 111 | } 112 | Log.v(TAG, "videoLength = "+videoLength + "s"); 113 | 114 | 115 | /** 116 | * 压缩视频 117 | */ 118 | CompressorUtils compressorUtils = new CompressorUtils(path,currentOutputVideoPath,MainActivity.this); 119 | compressorUtils.execCommand(new CompressListener() { 120 | @Override 121 | public void onExecSuccess(String message) { 122 | Log.i(TAG, "success " + message); 123 | progressBar.setVisibility(View.INVISIBLE); 124 | textAppend(getString(R.string.compress_succeed)); 125 | back.setText(getFileSize(currentOutputVideoPath)); 126 | //获取缩略图 127 | Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(currentOutputVideoPath, MediaStore.Video.Thumbnails.MINI_KIND); 128 | imag2.setImageBitmap(bitmap); 129 | } 130 | 131 | @Override 132 | public void onExecFail(String reason) { 133 | Log.i(TAG, "fail " + reason); 134 | } 135 | 136 | @Override 137 | public void onExecProgress(String message) { 138 | progressBar.setVisibility(View.VISIBLE); 139 | textAppend(getString(R.string.compress_progress, message)); 140 | 141 | int i = getProgress(message); 142 | Log.e("进度",i+""); 143 | progressBar.setProgress(i); 144 | } 145 | }); 146 | } 147 | }); 148 | 149 | image.setOnClickListener(new View.OnClickListener() { 150 | @Override 151 | public void onClick(View view) { 152 | openView(path); 153 | } 154 | }); 155 | imag2.setOnClickListener(new View.OnClickListener() { 156 | @Override 157 | public void onClick(View view) { 158 | openView(currentOutputVideoPath); 159 | } 160 | }); 161 | 162 | 163 | 164 | 165 | } 166 | 167 | /** 168 | * 小视屏录制回调 169 | * @param path 170 | */ 171 | @Override 172 | public void videoPathCall(String path) { 173 | 174 | Log.e("地址:",path); 175 | //根据视频地址获取缩略图 176 | this.path =path; 177 | Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(path, MediaStore.Video.Thumbnails.MINI_KIND); 178 | image.setImageBitmap(bitmap); 179 | first.setText(getFileSize(path)); 180 | 181 | 182 | } 183 | 184 | /** 185 | * 录制视频回调 186 | * @param requestCode 187 | * @param resultCode 188 | * @param data 189 | */ 190 | @Override 191 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 192 | if(requestCode==REQUEST_CODE_FOR_RECORD_VIDEO&&resultCode==RESULT_CANCELED){ 193 | 194 | } 195 | if(requestCode==REQUEST_CODE_FOR_RECORD_VIDEO&&resultCode==RESULT_OK){ 196 | String path = data.getStringExtra(VideoInputActivity.INTENT_EXTRA_VIDEO_PATH); 197 | Log.e("地址:",path); 198 | //根据视频地址获取缩略图 199 | this.path =path; 200 | Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(path, MediaStore.Video.Thumbnails.MINI_KIND); 201 | image.setImageBitmap(bitmap); 202 | first.setText(getFileSize(path)); 203 | } 204 | super.onActivityResult(requestCode, resultCode, data); 205 | } 206 | 207 | public void openView(String path){ 208 | if(TextUtils.isEmpty(path)){ 209 | 210 | return; 211 | } 212 | File file = new File(path); 213 | SystemAppUtils.openFile(file,this); 214 | } 215 | 216 | 217 | 218 | private String getFileSize(String path) { 219 | File f = new File(path); 220 | if (!f.exists()) { 221 | return "0 MB"; 222 | } else { 223 | long size = f.length(); 224 | return (size / 1024f) / 1024f + "MB"; 225 | } 226 | } 227 | int progress=0; 228 | private int getProgress(String source){ 229 | // Duration: 00:00:22.50, start: 0.000000, bitrate: 13995 kb/s 230 | 231 | //progress frame= 28 fps=0.0 q=24.0 size= 107kB time=00:00:00.91 bitrate= 956.4kbits/s 232 | if(source.contains("start: 0.000000")){ 233 | return progress; 234 | } 235 | Pattern p = Pattern.compile("00:\\d{2}:\\d{2}"); 236 | Matcher m = p.matcher(source); 237 | if (m.find()) { 238 | //00:00:00 239 | String result = m.group(0); 240 | String temp[] = result.split(":"); 241 | Double seconds = Double.parseDouble(temp[1]) * 60 + Double.parseDouble(temp[2]); 242 | 243 | if (0 != videoLength) { 244 | Log.v("进度长度", "current second = " + seconds+"/videoLength="+videoLength); 245 | progress = (int)(seconds *100/ videoLength); 246 | 247 | return progress; 248 | } 249 | return progress; 250 | } 251 | return progress; 252 | } 253 | 254 | 255 | private void textAppend(String text) { 256 | if (!TextUtils.isEmpty(text)) { 257 | Log.e("日志",text); 258 | } 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/jerei/videodemo/SystemAppUtils.java: -------------------------------------------------------------------------------- 1 | package com.example.jerei.videodemo; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.net.Uri; 7 | 8 | import java.io.File; 9 | 10 | /** 11 | * Created by zhush on 2016/10/24. 12 | * E-mail zhush@jerei.com 13 | */ 14 | 15 | public class SystemAppUtils { 16 | //文件类型后缀 17 | private static final String[][] MIME_MapTable = { { ".3gp", "video/3gpp" }, { ".apk", "application/vnd.android.package-archive" }, { ".asf", "video/x-ms-asf" }, { ".avi", "video/x-msvideo" }, { ".bin", "application/octet-stream" }, { ".bmp", "image/bmp" }, { ".c", "text/plain" }, { ".class", "application/octet-stream" }, { ".conf", "text/plain" }, { ".cpp", "text/plain" }, { ".doc", "application/msword" }, { ".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document" }, { ".xls", "application/vnd.ms-excel" }, { ".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }, { ".exe", "application/octet-stream" }, { ".gif", "image/gif" }, { ".gtar", "application/x-gtar" }, { ".gz", "application/x-gzip" }, { ".h", "text/plain" }, { ".htm", "text/html" }, { ".html", "text/html" }, { ".jar", "application/java-archive" }, { ".java", "text/plain" }, { ".jpeg", "image/jpeg" }, { ".jpg", "image/jpeg" }, { ".js", "application/x-javascript" }, { ".log", "text/plain" }, { ".m3u", "audio/x-mpegurl" }, { ".m4a", "audio/mp4a-latm" }, { ".m4b", "audio/mp4a-latm" }, { ".m4p", "audio/mp4a-latm" }, { ".m4u", "video/vnd.mpegurl" }, { ".m4v", "video/x-m4v" }, { ".mov", "video/quicktime" }, { ".mp2", "audio/x-mpeg" }, { ".mp3", "audio/x-mpeg" }, { ".mp4", "video/mp4" }, { ".mpc", "application/vnd.mpohun.certificate" }, { ".mpe", "video/mpeg" }, { ".mpeg", "video/mpeg" }, { ".mpg", "video/mpeg" }, { ".mpg4", "video/mp4" }, { ".mpga", "audio/mpeg" }, { ".msg", "application/vnd.ms-outlook" }, { ".ogg", "audio/ogg" }, { ".pdf", "application/pdf" }, { ".png", "image/png" }, { ".pps", "application/vnd.ms-powerpoint" }, { ".ppt", "application/vnd.ms-powerpoint" }, { ".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation" }, { ".prop", "text/plain" }, { ".rc", "text/plain" }, { ".rmvb", "audio/x-pn-realaudio" }, { ".rtf", "application/rtf" }, { ".sh", "text/plain" }, { ".tar", "application/x-tar" }, { ".tgz", "application/x-compressed" }, { ".txt", "text/plain" }, { ".wav", "audio/x-wav" }, { ".wma", "audio/x-ms-wma" }, { ".wmv", "audio/x-ms-wmv" }, { ".wps", "application/vnd.ms-works" }, { ".xml", "text/plain" }, { ".z", "application/x-compress" }, { ".zip", "application/x-zip-compressed" }, { "", "*/*" } }; 18 | 19 | 20 | /** 21 | * 打开文件 22 | * @param file 23 | */ 24 | public static void openFile(File file, Activity activity){ 25 | Intent intent = new Intent(Intent.ACTION_VIEW); 26 | String type = getMIMEType(file); 27 | Uri uri = Uri.fromFile(file); 28 | intent.setDataAndType(uri, type); 29 | activity.startActivity(intent); 30 | activity.overridePendingTransition(0, 0); 31 | } 32 | 33 | /** 34 | * 获取文件类型后缀 35 | * @param paramFile 36 | * @return 37 | */ 38 | private static String getMIMEType(File paramFile) 39 | { 40 | String str1 = "*/*"; 41 | String str2 = paramFile.getName(); 42 | int i = str2.lastIndexOf("."); 43 | if (i < 0) 44 | return str1; 45 | String str3 = str2.substring(i, str2.length()).toLowerCase(); 46 | if (str3 == "") 47 | return str1; 48 | for (int j = 0; ; j++) 49 | { 50 | if (j >= MIME_MapTable.length) 51 | return str1; 52 | if (str3.equals(MIME_MapTable[j][0])) 53 | str1 = MIME_MapTable[j][1]; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hui46226021/ShVideoDemo/65aa06fcf153371d2e36e2589110fdd7519baba4/app/src/main/res/drawable/btn_video.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_video_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hui46226021/ShVideoDemo/65aa06fcf153371d2e36e2589110fdd7519baba4/app/src/main/res/drawable/btn_video_hover.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_video_record.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/style_recorder_progress.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 10 | 11 |