├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── inspectionProfiles │ └── Project_Default.xml ├── markdown-exported-files.xml ├── markdown-navigator.xml ├── markdown-navigator │ └── profiles_settings.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── LICENSE.txt ├── aavt ├── .gitignore ├── bintrayUpload.gradle ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── wuwang │ │ └── aavt │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── shader │ │ │ ├── base.frag │ │ │ ├── base.vert │ │ │ ├── beauty │ │ │ ├── beauty.frag │ │ │ └── beauty.vert │ │ │ ├── color │ │ │ └── gray.frag │ │ │ ├── convert │ │ │ ├── eo_yuv420p.frag │ │ │ ├── export_yuv.frag │ │ │ ├── export_yuv420p.frag │ │ │ └── export_yuv420sp.frag │ │ │ ├── effect │ │ │ ├── fluorescence.frag │ │ │ ├── water_color.frag │ │ │ └── water_color_step1.frag │ │ │ ├── func │ │ │ ├── candy.frag │ │ │ ├── faltung3x3.frag │ │ │ ├── gauss.frag │ │ │ ├── sobel.frag │ │ │ └── sobel2.frag │ │ │ ├── oes.frag │ │ │ └── oes.vert │ ├── java │ │ └── com │ │ │ └── wuwang │ │ │ └── aavt │ │ │ ├── av │ │ │ ├── CameraRecorder2.java │ │ │ ├── Mp4Processor.java │ │ │ ├── Mp4Processor2.java │ │ │ ├── SurfaceRecorder.java │ │ │ └── VideoCapture.java │ │ │ ├── core │ │ │ ├── IObservable.java │ │ │ ├── IObserver.java │ │ │ ├── Observable.java │ │ │ └── Renderer.java │ │ │ ├── egl │ │ │ ├── EGLConfigAttrs.java │ │ │ ├── EGLContextAttrs.java │ │ │ └── EglHelper.java │ │ │ ├── expend │ │ │ └── SluggardFilterTool.java │ │ │ ├── gl │ │ │ ├── BaseFilter.java │ │ │ ├── BaseFuncFilter.java │ │ │ ├── BeautyFilter.java │ │ │ ├── BlackMagicFilter.java │ │ │ ├── CandyFilter.java │ │ │ ├── Faltung3x3Filter.java │ │ │ ├── FluorescenceFilter.java │ │ │ ├── FrameBuffer.java │ │ │ ├── GrayFilter.java │ │ │ ├── GroupFilter.java │ │ │ ├── LazyFilter.java │ │ │ ├── OesFilter.java │ │ │ ├── ProxyFilter.java │ │ │ ├── RollFilter.java │ │ │ ├── StickFigureFilter.java │ │ │ ├── WaterColorFilter.java │ │ │ ├── WaterMarkFilter.java │ │ │ └── YuvOutputFilter.java │ │ │ ├── log │ │ │ ├── AvLog.java │ │ │ ├── ConsoleLogger.java │ │ │ ├── EmptyLogger.java │ │ │ └── ILogger.java │ │ │ ├── media │ │ │ ├── CodecUtil.java │ │ │ ├── MediaConfig.java │ │ │ ├── RenderBean.java │ │ │ ├── SoundRecorder.java │ │ │ ├── SurfaceEncoder.java │ │ │ ├── SurfaceShower.java │ │ │ ├── VideoSurfaceProcessor.java │ │ │ ├── WrapRenderer.java │ │ │ ├── audio │ │ │ │ ├── FileAudioProvider.java │ │ │ │ ├── ISoundProvider.java │ │ │ │ └── MicAudioProvider.java │ │ │ ├── av │ │ │ │ ├── AvException.java │ │ │ │ ├── ICloseable.java │ │ │ │ └── IStore.java │ │ │ ├── hard │ │ │ │ ├── HardMediaData.java │ │ │ │ ├── IHardStore.java │ │ │ │ ├── MediaMuxerWraper.java │ │ │ │ ├── Mp4MuxStore.java │ │ │ │ ├── Recycler.java │ │ │ │ └── StrengthenMp4MuxStore.java │ │ │ ├── player │ │ │ │ ├── AudioDecoder.java │ │ │ │ ├── AudioPlayer.java │ │ │ │ ├── BaseAudioDecoder.java │ │ │ │ ├── BaseVideoDecoder.java │ │ │ │ ├── ByteBufferData.java │ │ │ │ ├── EPlayerException.java │ │ │ │ ├── EffectMediaPlayer.java │ │ │ │ ├── EffectMediaView.java │ │ │ │ ├── IAudioProcessor.java │ │ │ │ ├── IDecoder.java │ │ │ │ ├── ITextureProcessor.java │ │ │ │ ├── ITimeObserver.java │ │ │ │ ├── NormalAudioDecoder.java │ │ │ │ ├── NormalVideoDecoder.java │ │ │ │ └── VideoPlayer.java │ │ │ └── video │ │ │ │ ├── Camera2Provider.java │ │ │ │ ├── CameraProvider.java │ │ │ │ ├── ITextureProvider.java │ │ │ │ └── Mp4Provider.java │ │ │ └── utils │ │ │ ├── GpuUtils.java │ │ │ └── MatrixUtils.java │ └── res │ │ └── values │ │ ├── attr.xml │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── wuwang │ └── aavt │ └── ExampleUnitTest.java ├── build.gradle ├── examples ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── wuwang │ │ └── aavt │ │ └── examples │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── wuwang │ │ │ └── aavt │ │ │ └── examples │ │ │ ├── CameraRecorderActivity.java │ │ │ ├── ExampleMp4ProcessActivity.java │ │ │ ├── GetPathFromUri4kitkat.java │ │ │ ├── MainActivity.java │ │ │ ├── PermissionAsker.java │ │ │ ├── VideoPlayerActivity.java │ │ │ ├── VideoUtils.java │ │ │ └── YuvExportActivity.java │ └── res │ │ ├── drawable │ │ └── tv_start_bg.xml │ │ ├── layout │ │ ├── activity__export_yuv.xml │ │ ├── activity_camera_record.xml │ │ ├── activity_main.xml │ │ ├── activity_mp4.xml │ │ └── activity_player.xml │ │ ├── mipmap-hdpi │ │ ├── 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 │ └── wuwang │ └── aavt │ └── examples │ └── ExampleUnitTest.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── readme.md └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | /.idea/misc.xml 7 | .DS_Store 8 | /build 9 | /captures 10 | .externalNativeBuild 11 | -------------------------------------------------------------------------------- /.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/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 36 | -------------------------------------------------------------------------------- /.idea/markdown-exported-files.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/markdown-navigator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 36 | 37 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /.idea/markdown-navigator/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | 34 | 35 | 36 | 37 | 1.8 38 | 39 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /aavt/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /aavt/bintrayUpload.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.github.dcendents.android-maven' 2 | apply plugin: 'com.jfrog.bintray' 3 | // 配置版本 4 | version = rootProject.ext.vName 5 | 6 | // 定义相关网站 7 | def siteUrl = 'https://github.com/doggycoder/AAVT' // 项目的主页 8 | def gitUrl = 'https://github.com/doggycoder/AAVT.git' 9 | group = "com.wuwang.aavt" 10 | 11 | install { 12 | repositories.mavenInstaller { 13 | // This generates POM.xml with proper parameters 14 | pom { 15 | project { 16 | packaging 'aar' 17 | // Add your description here 18 | name 'Aavt' 19 | url siteUrl 20 | // Set your license 21 | licenses { 22 | license { 23 | name 'The Apache Software License, Version 2.0' 24 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt' 25 | } 26 | } 27 | developers { 28 | developer { 29 | id 'doggycoder' //填写的一些基本信息 30 | name 'doggycoder' 31 | email '158183202@qq.com' // 填写邮箱 32 | } 33 | } 34 | scm { 35 | connection gitUrl 36 | developerConnection gitUrl 37 | url siteUrl 38 | } 39 | } 40 | } 41 | } 42 | } 43 | 44 | // 打包 javadocjar 和 sourcejar 45 | task sourcesJar(type: Jar) { 46 | from android.sourceSets.main.java.srcDirs 47 | classifier = 'sources' 48 | } 49 | task javadoc(type: Javadoc) { 50 | source = android.sourceSets.main.java.srcDirs 51 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 52 | } 53 | task javadocJar(type: Jar, dependsOn: javadoc) { 54 | classifier = 'javadoc' 55 | from javadoc.destinationDir 56 | } 57 | artifacts { 58 | archives javadocJar 59 | archives sourcesJar 60 | } 61 | def propertiesFile = project.rootProject.file('local.properties') 62 | if(propertiesFile.exists()){ 63 | Properties properties = new Properties() 64 | properties.load(propertiesFile.newDataInputStream()) 65 | bintray { 66 | user = properties.getProperty("bintray.user") 67 | key = properties.getProperty("bintray.apikey") 68 | configurations = ['archives'] 69 | pkg { 70 | repo = "maven" 71 | name = "Aavt" //发布到JCenter上的项目名字 72 | websiteUrl = siteUrl 73 | vcsUrl = gitUrl 74 | licenses = ["Apache-2.0"] 75 | publish = true 76 | } 77 | } 78 | } 79 | 80 | javadoc { //jav doc采用utf-8编码否则会报“GBK的不可映射字符”错误 81 | options{ 82 | encoding "UTF-8" 83 | charSet 'UTF-8' 84 | links "http://docs.oracle.com/javase/7/docs/api" 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /aavt/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | group='com.wuwang.aavt' 4 | 5 | android { 6 | compileSdkVersion 25 7 | 8 | defaultConfig { 9 | minSdkVersion 14 10 | targetSdkVersion 25 11 | versionCode rootProject.ext.vCode 12 | versionName rootProject.ext.vName 13 | 14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 15 | 16 | } 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | } 24 | 25 | task buildMyJar(type: Jar, dependsOn: ['build']) { 26 | //导出的jar文件名称 27 | archiveName = 'Aavt.jar' 28 | //从哪个目录打包jar 29 | from('build/intermediates/classes/release/') 30 | destinationDir = file('output') 31 | //去掉不要的类 32 | exclude('**/BuildConfig.class') 33 | exclude('**/BuildConfig\$*.class') 34 | exclude('**/R.class') 35 | exclude('**/R\$*.class') 36 | include('com/wuwang/aavt/**') 37 | 38 | // doLast{ 39 | // copy { 40 | // from('libs/','build/intermediates/cmake/release/obj/') 41 | // into('output/') 42 | // } 43 | // } 44 | } 45 | 46 | dependencies { 47 | implementation fileTree(dir: 'libs', include: ['*.jar']) 48 | androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', { 49 | exclude group: 'com.android.support', module: 'support-annotations' 50 | }) 51 | implementation 'com.android.support:appcompat-v7:25.3.1' 52 | testImplementation 'junit:junit:4.12' 53 | } 54 | 55 | apply from: "bintrayUpload.gradle" 56 | -------------------------------------------------------------------------------- /aavt/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:\Android\android-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 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /aavt/src/androidTest/java/com/wuwang/aavt/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt; 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.wuwang.aavt.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /aavt/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /aavt/src/main/assets/shader/base.frag: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | varying vec2 vTextureCo; 3 | uniform sampler2D uTexture; 4 | void main() { 5 | gl_FragColor = texture2D( uTexture, vTextureCo); 6 | } -------------------------------------------------------------------------------- /aavt/src/main/assets/shader/base.vert: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | precision highp int; 3 | attribute vec4 aVertexCo; 4 | attribute vec2 aTextureCo; 5 | 6 | uniform mat4 uVertexMatrix; 7 | uniform mat4 uTextureMatrix; 8 | 9 | varying vec2 vTextureCo; 10 | 11 | void main(){ 12 | gl_Position = uVertexMatrix*aVertexCo; 13 | vTextureCo = (uTextureMatrix*vec4(aTextureCo,0,1)).xy; 14 | } -------------------------------------------------------------------------------- /aavt/src/main/assets/shader/beauty/beauty.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | precision highp int; 3 | uniform sampler2D uTexture; 4 | uniform int uIternum; 5 | uniform float uACoef; //参数 6 | uniform float uMixCoef; //混合系数 7 | varying highp vec2 vTextureCo; 8 | varying highp vec2 vBlurCoord1s[14]; 9 | const float distanceNormalizationFactor = 4.0; 10 | const mat3 saturateMatrix = mat3(1.1102,-0.0598,-0.061,-0.0774,1.0826,-0.1186,-0.0228,-0.0228,1.1772); 11 | 12 | void main() { 13 | 14 | vec3 centralColor; 15 | float central; 16 | float gaussianWeightTotal; 17 | float sum; 18 | float sampleColor; 19 | float distanceFromCentralColor; 20 | float gaussianWeight; 21 | 22 | central = texture2D( uTexture, vTextureCo ).g; 23 | gaussianWeightTotal = 0.2; 24 | sum = central * 0.2; 25 | 26 | for (int i = 0; i < 6; i++) { 27 | sampleColor = texture2D( uTexture, vBlurCoord1s[i] ).g; 28 | distanceFromCentralColor = min( abs( central - sampleColor ) * distanceNormalizationFactor, 1.0 ); 29 | gaussianWeight = 0.05 * (1.0 - distanceFromCentralColor); 30 | gaussianWeightTotal += gaussianWeight; 31 | sum += sampleColor * gaussianWeight; 32 | } 33 | for (int i = 6; i < 14; i++) { 34 | sampleColor = texture2D( uTexture, vBlurCoord1s[i] ).g; 35 | distanceFromCentralColor = min( abs( central - sampleColor ) * distanceNormalizationFactor, 1.0 ); 36 | gaussianWeight = 0.1 * (1.0 - distanceFromCentralColor); 37 | gaussianWeightTotal += gaussianWeight; 38 | sum += sampleColor * gaussianWeight; 39 | } 40 | 41 | sum = sum / gaussianWeightTotal; 42 | centralColor = texture2D( uTexture, vTextureCo ).rgb; 43 | sampleColor = centralColor.g - sum + 0.5; 44 | for (int i = 0; i < 100; i++) { 45 | if(i>=uIternum){ 46 | break; 47 | } 48 | if (sampleColor <= 0.5) { 49 | sampleColor = sampleColor * sampleColor * 2.0; 50 | } 51 | else { 52 | sampleColor = 1.0 - ((1.0 - sampleColor)*(1.0 - sampleColor) * 2.0); 53 | } 54 | } 55 | 56 | float aa = 1.0 + pow( centralColor.g, 0.3 )*uACoef; 57 | vec3 smoothColor = centralColor*aa - vec3( sampleColor )*(aa - 1.0); 58 | smoothColor = clamp( smoothColor, vec3( 0.0 ), vec3( 1.0 ) ); 59 | smoothColor = mix( centralColor, smoothColor, pow( centralColor.g, 0.33 ) ); 60 | smoothColor = mix( centralColor, smoothColor, pow( centralColor.g, uMixCoef ) ); 61 | gl_FragColor = vec4( pow( smoothColor, vec3( 0.96 ) ), 1.0 ); 62 | vec3 satcolor = gl_FragColor.rgb * saturateMatrix; 63 | gl_FragColor.rgb = mix( gl_FragColor.rgb, satcolor, 0.23 ); 64 | 65 | } -------------------------------------------------------------------------------- /aavt/src/main/assets/shader/beauty/beauty.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 aVertexCo; 2 | attribute vec2 aTextureCo; 3 | varying vec2 vTextureCo; 4 | varying vec2 vBlurCoord1s[14]; 5 | uniform float uWidth; 6 | uniform float uHeight; 7 | uniform mat4 uVertexMatrix; 8 | uniform mat4 uTextureMatrix; 9 | void main() 10 | { 11 | gl_Position = uVertexMatrix*aVertexCo; 12 | vTextureCo = (uTextureMatrix*vec4(aTextureCo,0,1)).xy; 13 | 14 | highp float mul_x = 2.0 / uWidth; 15 | highp float mul_y = 2.0 / uHeight; 16 | 17 | vBlurCoord1s[0] = vTextureCo + vec2( 0.0 * mul_x, -10.0 * mul_y ); 18 | vBlurCoord1s[1] = vTextureCo + vec2( 8.0 * mul_x, -5.0 * mul_y ); 19 | vBlurCoord1s[2] = vTextureCo + vec2( 8.0 * mul_x, 5.0 * mul_y ); 20 | vBlurCoord1s[3] = aTextureCo + vec2( 0.0 * mul_x, 10.0 * mul_y ); 21 | vBlurCoord1s[4] = aTextureCo + vec2( -8.0 * mul_x, 5.0 * mul_y ); 22 | vBlurCoord1s[5] = aTextureCo + vec2( -8.0 * mul_x, -5.0 * mul_y ); 23 | 24 | mul_x = 1.2 / uWidth; 25 | mul_y = 1.2 / uHeight; 26 | 27 | vBlurCoord1s[6] = aTextureCo + vec2( 0.0 * mul_x, -6.0 * mul_y ); 28 | vBlurCoord1s[7] = aTextureCo + vec2( -4.0 * mul_x, -4.0 * mul_y ); 29 | vBlurCoord1s[8] = aTextureCo + vec2( -6.0 * mul_x, 0.0 * mul_y ); 30 | vBlurCoord1s[9] = aTextureCo + vec2( -4.0 * mul_x, 4.0 * mul_y ); 31 | vBlurCoord1s[10] = aTextureCo + vec2( 0.0 * mul_x, 6.0 * mul_y ); 32 | vBlurCoord1s[11] = aTextureCo + vec2( 4.0 * mul_x, 4.0 * mul_y ); 33 | vBlurCoord1s[12] = aTextureCo + vec2( 6.0 * mul_x, 0.0 * mul_y ); 34 | vBlurCoord1s[13] = aTextureCo + vec2( 4.0 * mul_x, -4.0 * mul_y ); 35 | } -------------------------------------------------------------------------------- /aavt/src/main/assets/shader/color/gray.frag: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | varying vec2 vTextureCo; 3 | uniform sampler2D uTexture; 4 | const highp vec3 CO = vec3(0.2125, 0.7154, 0.0721); 5 | 6 | void main() { 7 | gl_FragColor=vec4(vec3(dot(texture2D( uTexture, vTextureCo).rgb,CO)),1.0); 8 | } -------------------------------------------------------------------------------- /aavt/src/main/assets/shader/convert/eo_yuv420p.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | precision highp int; 3 | 4 | varying vec2 vTextureCo; 5 | uniform sampler2D uTexture; 6 | 7 | //为了简化计算,宽高都必须为8的倍数 8 | uniform float uWidth; // 纹理宽 9 | uniform float uHeight; // 纹理高 10 | 11 | //转换公式 12 | //Y’= 0.299*R’ + 0.587*G’ + 0.114*B’ 13 | //U’= -0.147*R’ - 0.289*G’ + 0.436*B’ = 0.492*(B’- Y’) 14 | //V’= 0.615*R’ - 0.515*G’ - 0.100*B’ = 0.877*(R’- Y’) 15 | //导出原理:采样坐标只作为确定输出位置使用,通过输出纹理计算实际采样位置,进行采样和并转换, 16 | //然后将转换的结果填充到输出位置 17 | 18 | float cY(float x,float y){ 19 | vec4 c=texture2D(uTexture,vec2(x,y)); 20 | return c.r*0.2990+c.g*0.5870+c.b*0.1140; 21 | } 22 | 23 | float cU(float x,float y){ 24 | vec4 c=texture2D(uTexture,vec2(x,y)); 25 | return -0.1471*c.r - 0.2889*c.g + 0.4360*c.b+0.5000; 26 | } 27 | 28 | float cV(float x,float y){ 29 | vec4 c=texture2D(uTexture,vec2(x,y)); 30 | return 0.6150*c.r - 0.5150*c.g - 0.1000*c.b+0.5000; 31 | } 32 | 33 | vec2 cPos(float t,float shiftx,float gy){ 34 | vec2 pos=vec2(floor(uWidth*vTextureCo.x),floor(uHeight*gy)); 35 | return vec2(mod(pos.x*shiftx,uWidth),(pos.y*shiftx+floor(pos.x*shiftx/uWidth))*t); 36 | } 37 | 38 | //Y分量的计算 39 | vec4 calculateY(){ 40 | vec2 pos=cPos(1.,4.,vTextureCo.y); 41 | vec4 oColor=vec4(0); 42 | float textureYPos=pos.y/uHeight; 43 | oColor[0]=cY(pos.x/uWidth,textureYPos); 44 | oColor[1]=cY((pos.x+1.)/uWidth,textureYPos); 45 | oColor[2]=cY((pos.x+2.)/uWidth,textureYPos); 46 | oColor[3]=cY((pos.x+3.)/uWidth,textureYPos); 47 | return oColor; 48 | } 49 | 50 | //U分量的计算 51 | vec4 calculateU(){ 52 | vec2 pos=cPos(2.,8.,vTextureCo.y-0.2500); 53 | vec4 oColor=vec4(0); 54 | float textureYPos=pos.y/uHeight; 55 | oColor[0]= cU(pos.x/uWidth,textureYPos); 56 | oColor[1]= cU((pos.x+2.)/uWidth,textureYPos); 57 | oColor[2]= cU((pos.x+4.)/uWidth,textureYPos); 58 | oColor[3]= cU((pos.x+6.)/uWidth,textureYPos); 59 | return oColor; 60 | } 61 | 62 | //V分量计算 63 | vec4 calculateV(){ 64 | vec2 pos=cPos(2.,8.,vTextureCo.y-0.3125); 65 | vec4 oColor=vec4(0); 66 | float textureYPos=pos.y/uHeight; 67 | oColor[0]=cV(pos.x/uWidth,textureYPos); 68 | oColor[1]=cV((pos.x+2.)/uWidth,textureYPos); 69 | oColor[2]=cV((pos.x+4.)/uWidth,textureYPos); 70 | oColor[3]=cV((pos.x+6.)/uWidth,textureYPos); 71 | return oColor; 72 | } 73 | 74 | //UV的计算,YUV420SP用,test 75 | vec4 calculateUV(){ 76 | vec2 pos=cPos(2.,4.,vTextureCo.y-0.2500); 77 | vec4 oColor=vec4(0); 78 | float textureYPos=pos.y/uHeight; 79 | oColor[0]= cU(pos.x/uWidth,textureYPos); 80 | oColor[1]= cV(pos.x/uWidth,textureYPos); 81 | oColor[2]= cU((pos.x+2.)/uWidth,textureYPos); 82 | oColor[3]= cV((pos.x+2.)/uWidth,textureYPos); 83 | return oColor; 84 | } 85 | 86 | void main() { 87 | if(vTextureCo.y<0.2500){ 88 | gl_FragColor=calculateY(); 89 | }else if(vTextureCo.y<0.3125){ 90 | gl_FragColor=calculateU(); 91 | }else if(vTextureCo.y<0.3750){ 92 | gl_FragColor=calculateV(); 93 | }else{ 94 | gl_FragColor=vec4(0,0,0,0); 95 | } 96 | //gl_FragColor=vec4(rPosX/uWidth,rPosY/uHeight,rPosX/uWidth,rPosY/uHeight); 97 | } -------------------------------------------------------------------------------- /aavt/src/main/assets/shader/convert/export_yuv.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | precision highp int; 3 | 4 | varying vec2 vTextureCo; 5 | uniform sampler2D uTexture; 6 | 7 | uniform float uWidth; 8 | uniform float uHeight; 9 | 10 | float cY(float x,float y){ 11 | vec4 c=texture2D(uTexture,vec2(x,y)); 12 | return c.r*0.2126+c.g*0.7152+c.b*0.0722; 13 | } 14 | 15 | vec4 cC(float x,float y,float dx,float dy){ 16 | vec4 c0=texture2D(uTexture,vec2(x,y)); 17 | vec4 c1=texture2D(uTexture,vec2(x+dx,y)); 18 | vec4 c2=texture2D(uTexture,vec2(x,y+dy)); 19 | vec4 c3=texture2D(uTexture,vec2(x+dx,y+dy)); 20 | return (c0+c1+c2+c3)/4.; 21 | } 22 | 23 | float cU(float x,float y,float dx,float dy){ 24 | vec4 c=cC(x,y,dx,dy); 25 | return -0.09991*c.r - 0.33609*c.g + 0.43600*c.b+0.5000; 26 | } 27 | 28 | float cV(float x,float y,float dx,float dy){ 29 | vec4 c=cC(x,y,dx,dy); 30 | return 0.61500*c.r - 0.55861*c.g - 0.05639*c.b+0.5000; 31 | } 32 | 33 | vec2 cPos(float t,float shiftx,float gy){ 34 | vec2 pos=vec2(floor(uWidth*vTextureCo.x),floor(uHeight*gy)); 35 | return vec2(mod(pos.x*shiftx,uWidth),(pos.y*shiftx+floor(pos.x*shiftx/uWidth))*t); 36 | } 37 | 38 | vec4 calculateY(){ 39 | vec2 pos=cPos(1.,4.,vTextureCo.y); 40 | vec4 oColor=vec4(0); 41 | float textureYPos=pos.y/uHeight; 42 | oColor[0]=cY(pos.x/uWidth,textureYPos); 43 | oColor[1]=cY((pos.x+1.)/uWidth,textureYPos); 44 | oColor[2]=cY((pos.x+2.)/uWidth,textureYPos); 45 | oColor[3]=cY((pos.x+3.)/uWidth,textureYPos); 46 | return oColor; 47 | } 48 | vec4 calculateU(float gy,float dx,float dy){ 49 | vec2 pos=cPos(2.,8.,vTextureCo.y-gy); 50 | vec4 oColor=vec4(0); 51 | float textureYPos=pos.y/uHeight; 52 | oColor[0]= cU(pos.x/uWidth,textureYPos,dx,dy); 53 | oColor[1]= cU((pos.x+2.)/uWidth,textureYPos,dx,dy); 54 | oColor[2]= cU((pos.x+4.)/uWidth,textureYPos,dx,dy); 55 | oColor[3]= cU((pos.x+6.)/uWidth,textureYPos,dx,dy); 56 | return oColor; 57 | } 58 | vec4 calculateV(float gy,float dx,float dy){ 59 | vec2 pos=cPos(2.,8.,vTextureCo.y-gy); 60 | vec4 oColor=vec4(0); 61 | float textureYPos=pos.y/uHeight; 62 | oColor[0]=cV(pos.x/uWidth,textureYPos,dx,dy); 63 | oColor[1]=cV((pos.x+2.)/uWidth,textureYPos,dx,dy); 64 | oColor[2]=cV((pos.x+4.)/uWidth,textureYPos,dx,dy); 65 | oColor[3]=cV((pos.x+6.)/uWidth,textureYPos,dx,dy); 66 | return oColor; 67 | } 68 | vec4 calculateUV(float dx,float dy){ 69 | vec2 pos=cPos(2.,4.,vTextureCo.y-0.2500); 70 | vec4 oColor=vec4(0); 71 | float textureYPos=pos.y/uHeight; 72 | oColor[0]= cU(pos.x/uWidth,textureYPos,dx,dy); 73 | oColor[1]= cV(pos.x/uWidth,textureYPos,dx,dy); 74 | oColor[2]= cU((pos.x+2.)/uWidth,textureYPos,dx,dy); 75 | oColor[3]= cV((pos.x+2.)/uWidth,textureYPos,dx,dy); 76 | return oColor; 77 | } 78 | vec4 calculateVU(float dx,float dy){ 79 | vec2 pos=cPos(2.,4.,vTextureCo.y-0.2500); 80 | vec4 oColor=vec4(0); 81 | float textureYPos=pos.y/uHeight; 82 | oColor[0]= cV(pos.x/uWidth,textureYPos,dx,dy); 83 | oColor[1]= cU(pos.x/uWidth,textureYPos,dx,dy); 84 | oColor[2]= cV((pos.x+2.)/uWidth,textureYPos,dx,dy); 85 | oColor[3]= cU((pos.x+2.)/uWidth,textureYPos,dx,dy); 86 | return oColor; 87 | } 88 | -------------------------------------------------------------------------------- /aavt/src/main/assets/shader/convert/export_yuv420p.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | precision highp int; 3 | 4 | varying vec2 vTextureCo; 5 | uniform sampler2D uTexture; 6 | 7 | //为了简化计算,宽高都必须为8的倍数 8 | uniform float uWidth; // 纹理宽 9 | uniform float uHeight; // 纹理高 10 | 11 | //转换公式 12 | //Y’= 0.299*R’ + 0.587*G’ + 0.114*B’ 13 | //U’= -0.147*R’ - 0.289*G’ + 0.436*B’ = 0.492*(B’- Y’) 14 | //V’= 0.615*R’ - 0.515*G’ - 0.100*B’ = 0.877*(R’- Y’) 15 | //导出原理:采样坐标只作为确定输出位置使用,通过输出纹理计算实际采样位置,进行采样和并转换, 16 | //然后将转换的结果填充到输出位置 17 | 18 | float cY(float x,float y){ 19 | vec4 c=texture2D(uTexture,vec2(x,y)); 20 | return c.r*0.2990+c.g*0.5870+c.b*0.1140; 21 | } 22 | 23 | float cU(float x,float y){ 24 | vec4 c=texture2D(uTexture,vec2(x,y)); 25 | return -0.1471*c.r - 0.2889*c.g + 0.4360*c.b+0.5000; 26 | } 27 | 28 | float cV(float x,float y){ 29 | vec4 c=texture2D(uTexture,vec2(x,y)); 30 | return 0.6150*c.r - 0.5150*c.g - 0.1000*c.b+0.5000; 31 | } 32 | 33 | vec2 cPos(float t,float shiftx,float shifty){ 34 | vec2 pos=vec2(uWidth*vTextureCo.x,uHeight*(vTextureCo-shifty)); 35 | return vec2(mod(pos.x*shiftx,uWidth),(pos.y*shiftx+floor(pos.x*shiftx/uWidth))*t); 36 | } 37 | 38 | //Y分量的计算 39 | vec4 calculateY(){ 40 | //填充点对应图片的位置 41 | float posX=floor(uWidth*vTextureCo.x); 42 | float posY=floor(uHeight*vTextureCo.y); 43 | //实际采样起始点对应图片的位置 44 | float rPosX=mod(posX*4.,uWidth); 45 | float rPosY=posY*4.+floor(posX*4./uWidth); 46 | vec4 oColor=vec4(0); 47 | float textureYPos=rPosY/uHeight; 48 | oColor[0]=cY(rPosX/uWidth,textureYPos); 49 | oColor[1]=cY((rPosX+1.)/uWidth,textureYPos); 50 | oColor[2]=cY((rPosX+2.)/uWidth,textureYPos); 51 | oColor[3]=cY((rPosX+3.)/uWidth,textureYPos); 52 | return oColor; 53 | } 54 | 55 | 56 | //U分量的计算 57 | vec4 calculateU(){ 58 | //U的采样,宽度是1:8,高度是1:2,U的位置高度偏移了1/4,一个点是4个U,采样区域是宽高位8*2 59 | float posX=floor(uWidth*vTextureCo.x); 60 | float posY=floor(uHeight*(vTextureCo.y-0.2500)); 61 | //实际采样起始点对应图片的位置 62 | float rPosX=mod(posX*8.,uWidth); 63 | float rPosY=posY*16.+floor(posX*8./uWidth)*2.; 64 | 65 | vec4 oColor=vec4(0); 66 | oColor[0]= cU(rPosX/uWidth,rPosY/uHeight); 67 | oColor[1]= cU((rPosX+2.)/uWidth,rPosY/uHeight); 68 | oColor[2]= cU((rPosX+4.)/uWidth,rPosY/uHeight); 69 | oColor[3]= cU((rPosX+6.)/uWidth,rPosY/uHeight); 70 | return oColor; 71 | } 72 | 73 | //V分量计算 74 | vec4 calculateV(){ 75 | //V的采样,宽度是1:8,高度是1:2,U的位置高度偏移了1/4,一个点是4个V,采样区域是宽高位8*2 76 | float posX=floor(uWidth*vTextureCo.x); 77 | float posY=floor(uHeight*(vTextureCo.y-0.3125)); 78 | //实际采样起始点对应图片的位置 79 | float rPosX=mod(posX*8.,uWidth); 80 | float rPosY=posY*16.+floor(posX*8./uWidth)*2.; 81 | 82 | vec4 oColor=vec4(0); 83 | oColor[0]=cV(rPosX/uWidth,rPosY/uHeight); 84 | oColor[1]=cV((rPosX+2.)/uWidth,rPosY/uHeight); 85 | oColor[2]=cV((rPosX+4.)/uWidth,rPosY/uHeight); 86 | oColor[3]=cV((rPosX+6.)/uWidth,rPosY/uHeight); 87 | return oColor; 88 | } 89 | 90 | //UV的计算,YUV420SP用,test 91 | vec4 calculateUV(){ 92 | float posX=floor(uWidth*vTextureCo.x); 93 | float posY=floor(uHeight*(vTextureCo.y-0.2500)); 94 | //实际采样起始点对应图片的位置 95 | float rPosX=mod(posX*4.,uWidth); 96 | float rPosY=posY*8.+floor(posX*4./uWidth)*2.; 97 | vec4 oColor=vec4(0); 98 | oColor[0]= cU((rPosX+1.)/uWidth,(rPosY+1.)/uHeight); 99 | oColor[1]= cV((rPosX+1.)/uWidth,(rPosY+1.)/uHeight); 100 | oColor[2]= cU((rPosX+3.)/uWidth,(rPosY+1.)/uHeight); 101 | oColor[3]= cV((rPosX+3.)/uWidth,(rPosY+1.)/uHeight); 102 | return oColor; 103 | } 104 | 105 | void main() { 106 | if(vTextureCo.y<0.2500){ 107 | gl_FragColor=calculateY(); 108 | }else if(vTextureCo.y<0.3125){ 109 | gl_FragColor=calculateU(); 110 | }else if(vTextureCo.y<0.3750){ 111 | gl_FragColor=calculateV(); 112 | }else{ 113 | gl_FragColor=vec4(0,0,0,0); 114 | } 115 | //gl_FragColor=vec4(rPosX/uWidth,rPosY/uHeight,rPosX/uWidth,rPosY/uHeight); 116 | } -------------------------------------------------------------------------------- /aavt/src/main/assets/shader/convert/export_yuv420sp.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | precision highp int; 3 | 4 | varying vec2 vTextureCo; 5 | uniform sampler2D uTexture; 6 | 7 | //为了简化计算,宽高都必须为8的倍数 8 | uniform float uWidth; // 纹理宽 9 | uniform float uHeight; // 纹理高 10 | 11 | //转换公式 12 | //Y’= 0.299*R’ + 0.587*G’ + 0.114*B’ 13 | //U’= -0.147*R’ - 0.289*G’ + 0.436*B’ = 0.492*(B’- Y’) 14 | //V’= 0.615*R’ - 0.515*G’ - 0.100*B’ = 0.877*(R’- Y’) 15 | //导出原理:采样坐标只作为确定输出位置使用,通过输出纹理计算实际采样位置,进行采样和并转换, 16 | //然后将转换的结果填充到输出位置 17 | 18 | float cY(float x,float y){ 19 | vec4 c=texture2D(uTexture,vec2(x,y)); 20 | return c.r*0.2990+c.g*0.5870+c.b*0.1140; 21 | } 22 | 23 | float cU(float x,float y){ 24 | vec4 c=texture2D(uTexture,vec2(x,y)); 25 | return -0.1471*c.r - 0.2889*c.g + 0.4360*c.b+0.5000; 26 | } 27 | 28 | float cV(float x,float y){ 29 | vec4 c=texture2D(uTexture,vec2(x,y)); 30 | return 0.6150*c.r - 0.5150*c.g - 0.1000*c.b+0.5000; 31 | } 32 | 33 | vec2 cPos(float t,float shiftx,float shifty){ 34 | vec2 pos=vec2(uWidth*vTextureCo.x,uHeight*(vTextureCo-shifty)); 35 | return vec2(mod(pos.x*shiftx,uWidth),(pos.y*shiftx+floor(pos.x*shiftx/uWidth))*t); 36 | } 37 | 38 | //Y分量的计算 39 | vec4 calculateY(){ 40 | //填充点对应图片的位置 41 | float posX=floor(uWidth*vTextureCo.x); 42 | float posY=floor(uHeight*vTextureCo.y); 43 | //实际采样起始点对应图片的位置 44 | float rPosX=mod(posX*4.,uWidth); 45 | float rPosY=posY*4.+floor(posX*4./uWidth); 46 | vec4 oColor=vec4(0); 47 | float textureYPos=rPosY/uHeight; 48 | oColor[0]=cY(rPosX/uWidth,textureYPos); 49 | oColor[1]=cY((rPosX+1.)/uWidth,textureYPos); 50 | oColor[2]=cY((rPosX+2.)/uWidth,textureYPos); 51 | oColor[3]=cY((rPosX+3.)/uWidth,textureYPos); 52 | return oColor; 53 | } 54 | gi git 55 | void main() { 56 | if(vTextureCo.y<0.2500){ 57 | gl_FragColor=calculateY(); 58 | }else if(vTextureCo.y<0.3750){ 59 | gl_FragColor=calculateUV(); 60 | }else{ 61 | gl_FragColor=vec4(0,0,0,0); 62 | } 63 | } -------------------------------------------------------------------------------- /aavt/src/main/assets/shader/effect/fluorescence.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform sampler2D uTexture; 4 | uniform sampler2D uTexture2; 5 | uniform float uWidth; 6 | uniform float uHeight; 7 | varying vec2 vTextureCo; 8 | 9 | uniform vec4 uBorderColor; 10 | uniform float uStep; 11 | 12 | void main(){ 13 | vec4 baseColor=texture2D(uTexture,vTextureCo); 14 | float sobelColor=texture2D(uTexture2,vTextureCo).r; 15 | gl_FragColor=(1.-sobelColor*uStep)*baseColor+sobelColor*uBorderColor*uStep; 16 | } -------------------------------------------------------------------------------- /aavt/src/main/assets/shader/effect/water_color.frag: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | 3 | uniform sampler2D uTexture; 4 | uniform sampler2D uNoiseTexture; 5 | uniform float uWidth; 6 | uniform float uHeight; 7 | varying vec2 vTextureCo; 8 | 9 | vec4 valueAdd(vec2 pos,float shiftX,float shiftY,float p){ 10 | vec2 newPos=vec2((pos.x+shiftX)/uWidth,(pos.y+shiftY)/uHeight); 11 | return texture2D(uTexture,newPos)/p; 12 | } 13 | 14 | void main(){ 15 | float step=floor(uWidth/128.); 16 | vec2 xy = vec2(vTextureCo.x * uWidth, vTextureCo.y * uHeight); 17 | vec4 color=valueAdd(xy,0.,0.,4.); 18 | color+=valueAdd(xy,-step,-step,16.); 19 | color+=valueAdd(xy,-step,step,8.); 20 | color+=valueAdd(xy,-step,step,16.); 21 | color+=valueAdd(xy,step,-step,8.); 22 | color+=valueAdd(xy,step,step,8.); 23 | color+=valueAdd(xy,step,-step,16.); 24 | color+=valueAdd(xy,step,step,8.); 25 | color+=valueAdd(xy,step,step,16.); 26 | gl_FragColor = color; 27 | } -------------------------------------------------------------------------------- /aavt/src/main/assets/shader/effect/water_color_step1.frag: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | 3 | uniform sampler2D uTexture; 4 | uniform sampler2D uNoiseTexture; 5 | uniform float uWidth; 6 | uniform float uHeight; 7 | varying vec2 vTextureCo; 8 | 9 | vec4 quant(vec4 cl, float n) { 10 | cl.x = floor(cl.x * 255./n)*n/255.; 11 | cl.y = floor(cl.y * 255./n)*n/255.; 12 | cl.z = floor(cl.z * 255./n)*n/255.; 13 | 14 | return cl; 15 | } 16 | 17 | void main(void){ 18 | vec4 noiseColor = texture2D(uNoiseTexture, vTextureCo); 19 | vec2 newUV = vec2(vTextureCo.x + noiseColor.x / uWidth, vTextureCo.y + noiseColor.y / uHeight); 20 | vec4 fColor = texture2D(uTexture, newUV); 21 | 22 | vec4 color = quant(fColor, 255./pow(2., 4.)); 23 | //vec4 color = vec4(1., 1., .5, 1.); 24 | gl_FragColor = color; 25 | } -------------------------------------------------------------------------------- /aavt/src/main/assets/shader/func/candy.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform sampler2D uTexture; 4 | uniform float uWidth; 5 | uniform float uHeight; 6 | varying vec2 vTextureCo; 7 | const float step=1.; 8 | const mat3 GX=mat3(-1.,0., +1., -2., 0., +2., -1., 0., +1.); 9 | const mat3 GY=mat3(-1., -2., -1., 0., 0., 0., +1., +2., +1.); 10 | 11 | //sobel 算子有两个滤波矩阵Gx和Gy,注意: 12 | //边缘检测时Gx为检测纵向边缘,Gy为检测横向边缘 13 | //计算法线时Gx为计算法线的横向偏移,Gy为计算法线的纵向偏移 14 | //Gx为[-1 0 +1 -2 0 +2 -1 0 +1] 3*3矩阵 15 | //Gy为[-1 -2 -1 0 0 0 +1 +2 +1] 3*3矩阵 16 | 17 | //candy 最主要的是在sobel的基础上做非最大值抑制 18 | //非最大值抑制前,先要更具Gx和Gy得到强度梯度 19 | 20 | float colorR(vec2 center,float shiftX,float shiftY){ 21 | return texture2D(uTexture,vec2(vTextureCo.x+shiftX/uWidth,vTextureCo.y+shiftY/uHeight)).r; 22 | } 23 | 24 | void main(){ 25 | vec2 center=vec2(vTextureCo.x*uWidth,vTextureCo.y*uHeight); 26 | float leftTop=colorR(center,-step,-step); 27 | float centerTop=colorR(center,0.,-step); 28 | float rightTop=colorR(center,step,-step); 29 | float leftCenter=colorR(center,-step,0.); 30 | float rightCenter=colorR(center,step,0.); 31 | float leftBottom=colorR(center,-step,step); 32 | float centerBottom=colorR(center,0.,step); 33 | float rightBottom=colorR(center,step,step); 34 | mat3 d=mat3(colorR(center,-step,-step),colorR(center,0.,-step),colorR(center,step,-step), 35 | colorR(center,-step,0.),colorR(center,0.,0.),colorR(center,step,0.), 36 | colorR(center,-step,step),colorR(center,0.,step),colorR(center,step,step)); 37 | //计算Gx Gy 38 | float x = d[0][0]*GX[0][0]+d[1][0]*GX[1][0]+d[2][0]*GX[2][0]+ 39 | d[0][1]*GX[0][1]+d[1][1]*GX[1][1]+d[2][1]*GX[2][1]+ 40 | d[0][2]*GX[0][2]+d[1][2]*GX[1][2]+d[2][2]*GX[2][2]; 41 | float y = d[0][0]*GY[0][0]+d[1][0]*GY[1][0]+d[2][0]*GY[2][0]+ 42 | d[0][1]*GY[0][1]+d[1][1]*GY[1][1]+d[2][1]*GY[2][1]+ 43 | d[0][2]*GY[0][2]+d[1][2]*GY[1][2]+d[2][2]*GY[2][2]; 44 | 45 | //计算强度梯度 46 | float G=length(vec2(x,y)); 47 | float thita=atan(y,x); 48 | gl_FragColor=vec4(vec3(G),1.); 49 | } -------------------------------------------------------------------------------- /aavt/src/main/assets/shader/func/faltung3x3.frag: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | varying vec2 vTextureCo; 3 | uniform sampler2D uTexture; 4 | uniform mat3 uFaltung; 5 | uniform float uWidth; 6 | uniform float uHeight; 7 | 8 | 9 | vec4 getColor(float x,float y,float p){ 10 | return p*texture2D(uTexture,vec2(x/uWidth,y/uHeight)+vTextureCo); 11 | } 12 | 13 | void main() { 14 | 15 | vec4 color; 16 | 17 | color+=getColor(-1.,-1.,uFaltung[0][0]); 18 | color+=getColor(0.,-1.,uFaltung[1][0]); 19 | color+=getColor(1.,-1.,uFaltung[2][0]); 20 | 21 | color+=getColor(-1.,0.,uFaltung[0][1]); 22 | color+=getColor(0.,0.,uFaltung[1][1]); 23 | color+=getColor(1.,0.,uFaltung[2][1]); 24 | 25 | color+=getColor(-1.,1.,uFaltung[0][2]); 26 | color+=getColor(0.,1.,uFaltung[1][2]); 27 | color+=getColor(1.,1.,uFaltung[2][2]); 28 | 29 | gl_FragColor = color; 30 | } -------------------------------------------------------------------------------- /aavt/src/main/assets/shader/func/gauss.frag: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | varying vec2 vTextureCo; 3 | uniform sampler2D uTexture; 4 | uniform float uWidth; 5 | uniform float uHeight; 6 | 7 | 8 | vec4 getColor(float x,float y,float p){ 9 | return p*texture2D(uTexture,vec2(x/uWidth,y/uHeight)+vTextureCo); 10 | } 11 | 12 | void main() { 13 | 14 | vec4 color; 15 | 16 | color+=getColor(-2.,-2.,2.); 17 | color+=getColor(-1.,-2.,4.); 18 | color+=getColor(0.,-2.,5.); 19 | color+=getColor(1.,-2.,4.); 20 | color+=getColor(2.,-2.,2.); 21 | 22 | color+=getColor(-2.,-1.,4.); 23 | color+=getColor(-1.,-1.,9.); 24 | color+=getColor(0.,-1.,12.); 25 | color+=getColor(1.,-1.,9.); 26 | color+=getColor(2.,-1.,4.); 27 | 28 | color+=getColor(-2.,1.,4.); 29 | color+=getColor(-1.,1.,9.); 30 | color+=getColor(0.,1.,12.); 31 | color+=getColor(1.,1.,9.); 32 | color+=getColor(2.,1.,4.); 33 | 34 | color+=getColor(-2.,0.,9.); 35 | color+=getColor(-1.,0.,12.); 36 | color+=getColor(0.,0.,15.); 37 | color+=getColor(1.,0.,12.); 38 | color+=getColor(2.,0.,9.); 39 | 40 | color+=getColor(-2.,2.,2.); 41 | color+=getColor(-1.,2.,4.); 42 | color+=getColor(0.,2.,5.); 43 | color+=getColor(1.,2.,4.); 44 | color+=getColor(2.,2.,2.); 45 | 46 | gl_FragColor = color/159.; 47 | } -------------------------------------------------------------------------------- /aavt/src/main/assets/shader/func/sobel.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform sampler2D uTexture; 4 | uniform float uWidth; 5 | uniform float uHeight; 6 | varying vec2 vTextureCo; 7 | const float step=1.; 8 | const mat3 GX=mat3(-1.,0., +1., -2., 0., +2., -1., 0., +1.); 9 | const mat3 GY=mat3(-1., -2., -1., 0., 0., 0., +1., +2., +1.); 10 | 11 | //sobel 算子有两个滤波矩阵Gx和Gy,注意: 12 | //边缘检测时Gx为检测纵向边缘,Gy为检测横向边缘 13 | //计算法线时Gx为计算法线的横向偏移,Gy为计算法线的纵向偏移 14 | //Gx为[-1 0 +1 -2 0 +2 -1 0 +1] 3*3矩阵 15 | //Gy为[-1 -2 -1 0 0 0 +1 +2 +1] 3*3矩阵 16 | 17 | float colorR(vec2 center,float shiftX,float shiftY){ 18 | return texture2D(uTexture,vec2(vTextureCo.x+shiftX/uWidth,vTextureCo.y+shiftY/uHeight)).r; 19 | } 20 | 21 | void main(){ 22 | vec2 center=vec2(vTextureCo.x*uWidth,vTextureCo.y*uHeight); 23 | float leftTop=colorR(center,-step,-step); 24 | float centerTop=colorR(center,0.,-step); 25 | float rightTop=colorR(center,step,-step); 26 | float leftCenter=colorR(center,-step,0.); 27 | float rightCenter=colorR(center,step,0.); 28 | float leftBottom=colorR(center,-step,step); 29 | float centerBottom=colorR(center,0.,step); 30 | float rightBottom=colorR(center,step,step); 31 | mat3 d=mat3(colorR(center,-step,-step),colorR(center,0.,-step),colorR(center,step,-step), 32 | colorR(center,-step,0.),colorR(center,0.,0.),colorR(center,step,0.), 33 | colorR(center,-step,step),colorR(center,0.,step),colorR(center,step,step)); 34 | float x = d[0][0]*GX[0][0]+d[1][0]*GX[1][0]+d[2][0]*GX[2][0]+ 35 | d[0][1]*GX[0][1]+d[1][1]*GX[1][1]+d[2][1]*GX[2][1]+ 36 | d[0][2]*GX[0][2]+d[1][2]*GX[1][2]+d[2][2]*GX[2][2]; 37 | float y = d[0][0]*GY[0][0]+d[1][0]*GY[1][0]+d[2][0]*GY[2][0]+ 38 | d[0][1]*GY[0][1]+d[1][1]*GY[1][1]+d[2][1]*GY[2][1]+ 39 | d[0][2]*GY[0][2]+d[1][2]*GY[1][2]+d[2][2]*GY[2][2]; 40 | gl_FragColor=vec4(vec3(length(vec2(x,y))),1.); 41 | } -------------------------------------------------------------------------------- /aavt/src/main/assets/shader/func/sobel2.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform sampler2D uTexture; 4 | uniform float uWidth; 5 | uniform float uHeight; 6 | varying vec2 vTextureCo; 7 | const float step=1.; 8 | const mat3 GX=mat3(-1.,0., +1., -1., 0., +1., -1., 0., +1.); 9 | const mat3 GY=mat3(-1., -1., -1., 0., 0., 0., +1., +1., +1.); 10 | 11 | //sobel 算子有两个滤波矩阵Gx和Gy,注意: 12 | //边缘检测时Gx为检测纵向边缘,Gy为检测横向边缘 13 | //计算法线时Gx为计算法线的横向偏移,Gy为计算法线的纵向偏移 14 | //Gx为[-1 0 +1 -2 0 +2 -1 0 +1] 3*3矩阵 15 | //Gy为[-1 -2 -1 0 0 0 +1 +2 +1] 3*3矩阵 16 | 17 | float colorR(vec2 center,float shiftX,float shiftY){ 18 | return texture2D(uTexture,vec2(vTextureCo.x+shiftX/uWidth,vTextureCo.y+shiftY/uHeight)).r; 19 | } 20 | 21 | void main(){ 22 | vec2 center=vec2(vTextureCo.x*uWidth,vTextureCo.y*uHeight); 23 | float leftTop=colorR(center,-step,-step); 24 | float centerTop=colorR(center,0.,-step); 25 | float rightTop=colorR(center,step,-step); 26 | float leftCenter=colorR(center,-step,0.); 27 | float rightCenter=colorR(center,step,0.); 28 | float leftBottom=colorR(center,-step,step); 29 | float centerBottom=colorR(center,0.,step); 30 | float rightBottom=colorR(center,step,step); 31 | mat3 d=mat3(colorR(center,-step,-step),colorR(center,0.,-step),colorR(center,step,-step), 32 | colorR(center,-step,0.),colorR(center,0.,0.),colorR(center,step,0.), 33 | colorR(center,-step,step),colorR(center,0.,step),colorR(center,step,step)); 34 | float x = d[0][0]*GX[0][0]+d[1][0]*GX[1][0]+d[2][0]*GX[2][0]+ 35 | d[0][1]*GX[0][1]+d[1][1]*GX[1][1]+d[2][1]*GX[2][1]+ 36 | d[0][2]*GX[0][2]+d[1][2]*GX[1][2]+d[2][2]*GX[2][2]; 37 | float y = d[0][0]*GY[0][0]+d[1][0]*GY[1][0]+d[2][0]*GY[2][0]+ 38 | d[0][1]*GY[0][1]+d[1][1]*GY[1][1]+d[2][1]*GY[2][1]+ 39 | d[0][2]*GY[0][2]+d[1][2]*GY[1][2]+d[2][2]*GY[2][2]; 40 | gl_FragColor=vec4(vec3(1.)-vec3(length(vec2(x,y))),1.); 41 | } -------------------------------------------------------------------------------- /aavt/src/main/assets/shader/oes.frag: -------------------------------------------------------------------------------- 1 | #extension GL_OES_EGL_image_external : require 2 | precision mediump float; 3 | varying vec2 vTextureCo; 4 | uniform samplerExternalOES uTexture; 5 | void main() { 6 | gl_FragColor = texture2D( uTexture, vTextureCo); 7 | } -------------------------------------------------------------------------------- /aavt/src/main/assets/shader/oes.vert: -------------------------------------------------------------------------------- 1 | attribute vec4 aVertexCo; 2 | attribute vec2 aTextureCo; 3 | 4 | uniform mat4 uVertexMatrix; 5 | uniform mat4 uTextureMatrix; 6 | 7 | varying vec2 vTextureCo; 8 | 9 | void main(){ 10 | gl_Position = uVertexMatrix*aVertexCo; 11 | vTextureCo = (uTextureMatrix*vec4(aTextureCo,0,1)).xy; 12 | } -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/av/CameraRecorder2.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.av; 15 | 16 | import android.content.Context; 17 | 18 | import com.wuwang.aavt.core.Renderer; 19 | import com.wuwang.aavt.media.video.Camera2Provider; 20 | import com.wuwang.aavt.media.video.ITextureProvider; 21 | import com.wuwang.aavt.media.SurfaceEncoder; 22 | import com.wuwang.aavt.media.SoundRecorder; 23 | import com.wuwang.aavt.media.SurfaceShower; 24 | import com.wuwang.aavt.media.VideoSurfaceProcessor; 25 | import com.wuwang.aavt.media.av.AvException; 26 | import com.wuwang.aavt.media.hard.IHardStore; 27 | import com.wuwang.aavt.media.hard.StrengthenMp4MuxStore; 28 | 29 | /** 30 | * CameraRecorder2 相机预览及录制工具类 31 | * 32 | * @author wuwang 33 | * @version v1.0 2017:10:26 18:35 34 | */ 35 | public class CameraRecorder2 { 36 | 37 | private VideoSurfaceProcessor mTextureProcessor; 38 | private ITextureProvider mCameraProvider; 39 | private SurfaceShower mShower; 40 | private SurfaceEncoder mSurfaceStore; 41 | private IHardStore mMuxer; 42 | 43 | private SoundRecorder mSoundRecord; 44 | 45 | public CameraRecorder2(Context context){ 46 | //用于视频混流和存储 47 | mMuxer=new StrengthenMp4MuxStore(true); 48 | 49 | //用于预览图像 50 | mShower=new SurfaceShower(); 51 | mShower.setOutputSize(720,1280); 52 | 53 | //用于编码图像 54 | mSurfaceStore=new SurfaceEncoder(); 55 | mSurfaceStore.setStore(mMuxer); 56 | 57 | //用于音频 58 | mSoundRecord=new SoundRecorder(mMuxer); 59 | 60 | //用于处理视频图像 61 | mTextureProcessor=new VideoSurfaceProcessor(); 62 | mTextureProcessor.setTextureProvider(mCameraProvider=new Camera2Provider(context)); 63 | mTextureProcessor.addObserver(mShower); 64 | mTextureProcessor.addObserver(mSurfaceStore); 65 | } 66 | 67 | public void setRenderer(Renderer renderer){ 68 | mTextureProcessor.setRenderer(renderer); 69 | } 70 | 71 | /** 72 | * 设置预览对象,必须是{@link android.view.Surface}、{@link android.graphics.SurfaceTexture}或者 73 | * {@link android.view.TextureView} 74 | * @param surface 预览对象 75 | */ 76 | public void setSurface(Object surface){ 77 | mShower.setSurface(surface); 78 | } 79 | 80 | /** 81 | * 设置录制的输出路径 82 | * @param path 输出路径 83 | */ 84 | public void setOutputPath(String path){ 85 | mMuxer.setOutputPath(path); 86 | } 87 | 88 | /** 89 | * 设置预览大小 90 | * @param width 预览区域宽度 91 | * @param height 预览区域高度 92 | */ 93 | public void setPreviewSize(int width,int height){ 94 | mShower.setOutputSize(width,height); 95 | } 96 | 97 | /** 98 | * 打开数据源 99 | */ 100 | public void open(){ 101 | mTextureProcessor.start(); 102 | } 103 | 104 | /** 105 | * 关闭数据源 106 | */ 107 | public void close(){ 108 | mTextureProcessor.stop(); 109 | stopRecord(); 110 | } 111 | 112 | /** 113 | * 打开预览 114 | */ 115 | public void startPreview(){ 116 | mShower.open(); 117 | } 118 | 119 | /** 120 | * 关闭预览 121 | */ 122 | public void stopPreview(){ 123 | mShower.close(); 124 | } 125 | 126 | /** 127 | * 开始录制 128 | */ 129 | public void startRecord(){ 130 | mSurfaceStore.open(); 131 | mSoundRecord.start(); 132 | } 133 | 134 | /** 135 | * 关闭录制 136 | */ 137 | public void stopRecord(){ 138 | mSoundRecord.stop(); 139 | mSurfaceStore.close(); 140 | mMuxer.close(); 141 | } 142 | 143 | } 144 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/av/Mp4Processor2.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.av; 15 | 16 | import com.wuwang.aavt.media.video.Mp4Provider; 17 | import com.wuwang.aavt.media.SurfaceEncoder; 18 | import com.wuwang.aavt.media.SurfaceShower; 19 | import com.wuwang.aavt.media.VideoSurfaceProcessor; 20 | import com.wuwang.aavt.media.hard.IHardStore; 21 | import com.wuwang.aavt.media.hard.StrengthenMp4MuxStore; 22 | 23 | /** 24 | * Mp4Processor2 用于处理Mp4文件 25 | * 26 | * @author wuwang 27 | * @version v1.0 2017:10:26 18:48 28 | */ 29 | public class Mp4Processor2 { 30 | 31 | private VideoSurfaceProcessor mTextureProcessor; 32 | private Mp4Provider mMp4Provider; 33 | private SurfaceShower mShower; 34 | private SurfaceEncoder mSurfaceStore; 35 | private IHardStore mMuxer; 36 | 37 | public Mp4Processor2(){ 38 | //用于视频混流和存储 39 | mMuxer=new StrengthenMp4MuxStore(true); 40 | 41 | //用于预览图像 42 | mShower=new SurfaceShower(); 43 | mShower.setOutputSize(720,1280); 44 | 45 | //用于编码图像 46 | mSurfaceStore=new SurfaceEncoder(); 47 | mSurfaceStore.setStore(mMuxer); 48 | 49 | //用于音频 50 | // mSoundRecord=new SoundRecorder(mMuxer); 51 | mMp4Provider=new Mp4Provider(); 52 | mMp4Provider.setStore(mMuxer); 53 | 54 | //用于处理视频图像 55 | mTextureProcessor=new VideoSurfaceProcessor(); 56 | mTextureProcessor.setTextureProvider(mMp4Provider); 57 | mTextureProcessor.addObserver(mShower); 58 | mTextureProcessor.addObserver(mSurfaceStore); 59 | } 60 | 61 | public void setSurface(Object surface){ 62 | mShower.setSurface(surface); 63 | } 64 | 65 | public void setInputPath(String path){ 66 | mMp4Provider.setInputPath(path); 67 | } 68 | 69 | public void setOutputPath(String path){ 70 | mMuxer.setOutputPath(path); 71 | } 72 | 73 | public void setPreviewSize(int width,int height){ 74 | mShower.setOutputSize(width,height); 75 | } 76 | 77 | public void open(){ 78 | mTextureProcessor.start(); 79 | } 80 | 81 | public void close(){ 82 | mTextureProcessor.stop(); 83 | } 84 | 85 | public void startPreview(){ 86 | mShower.open(); 87 | } 88 | 89 | public void stopPreview(){ 90 | mShower.close(); 91 | } 92 | 93 | public void startRecord(){ 94 | mSurfaceStore.open(); 95 | // mSoundRecord.start(); 96 | } 97 | 98 | public void stopRecord(){ 99 | mSurfaceStore.close(); 100 | // mSoundRecord.stop(); 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/av/SurfaceRecorder.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.av; 2 | 3 | import android.content.Context; 4 | 5 | import com.wuwang.aavt.core.Renderer; 6 | import com.wuwang.aavt.media.video.Camera2Provider; 7 | import com.wuwang.aavt.media.video.ITextureProvider; 8 | import com.wuwang.aavt.media.SoundRecorder; 9 | import com.wuwang.aavt.media.SurfaceEncoder; 10 | import com.wuwang.aavt.media.SurfaceShower; 11 | import com.wuwang.aavt.media.VideoSurfaceProcessor; 12 | import com.wuwang.aavt.media.av.AvException; 13 | import com.wuwang.aavt.media.hard.IHardStore; 14 | import com.wuwang.aavt.media.hard.StrengthenMp4MuxStore; 15 | 16 | /** 17 | * @author wuwang 18 | * @version 1.00 , 2018/11/14 19 | */ 20 | public class SurfaceRecorder { 21 | 22 | private Context context; 23 | private VideoSurfaceProcessor mTextureProcessor; 24 | private SurfaceShower mShower; 25 | private SurfaceEncoder mSurfaceStore; 26 | private IHardStore mMuxer; 27 | 28 | private ITextureProvider mProvider; 29 | private SoundRecorder mSoundRecord; 30 | 31 | private int mPreviewWidth = 720; 32 | private int mPreviewHeight = 1280; 33 | private int mRecordWidth = 720; 34 | private int mRecordHeight = 1280; 35 | private String path; 36 | private Renderer mRender; 37 | private Object mShowSurface; 38 | 39 | public SurfaceRecorder(Context context){ 40 | this.context = context; 41 | } 42 | 43 | public void setTextureProvider(ITextureProvider provider){ 44 | this.mProvider = provider; 45 | } 46 | 47 | public void setPreviewSize(int width,int height){ 48 | this.mPreviewWidth = width; 49 | this.mPreviewHeight = height; 50 | } 51 | 52 | public void setRecordSize(int width,int height){ 53 | this.mRecordWidth = width; 54 | this.mRecordHeight = height; 55 | } 56 | 57 | public void setSurface(Object surface){ 58 | this.mShowSurface = surface; 59 | } 60 | 61 | /** 62 | * 设置录制的输出路径 63 | * @param path 输出路径 64 | */ 65 | public void setOutputPath(String path){ 66 | this.path = path; 67 | } 68 | 69 | public void setRenderer(Renderer renderer){ 70 | this.mRender = renderer; 71 | } 72 | 73 | public void open(){ 74 | if(mMuxer == null){ 75 | mMuxer=new StrengthenMp4MuxStore(true); 76 | mMuxer.setOutputPath(path); 77 | } 78 | 79 | if(mProvider == null){ 80 | mProvider=new Camera2Provider(context); 81 | } 82 | 83 | if(mShower == null){ 84 | //用于预览图像 85 | mShower=new SurfaceShower(); 86 | mShower.setOutputSize(mPreviewWidth,mPreviewHeight); 87 | mShower.setSurface(mShowSurface); 88 | } 89 | 90 | if(mSurfaceStore == null){ 91 | //用于编码图像 92 | mSurfaceStore=new SurfaceEncoder(); 93 | mSurfaceStore.setOutputSize(mRecordWidth,mRecordHeight); 94 | mSurfaceStore.setStore(mMuxer); 95 | } 96 | 97 | if(mSoundRecord == null){ 98 | //用于音频 99 | mSoundRecord=new SoundRecorder(mMuxer); 100 | } 101 | 102 | if(mTextureProcessor == null){ 103 | //用于处理视频图像 104 | mTextureProcessor=new VideoSurfaceProcessor(); 105 | mTextureProcessor.setTextureProvider(mProvider); 106 | mTextureProcessor.addObserver(mShower); 107 | mTextureProcessor.addObserver(mSurfaceStore); 108 | mTextureProcessor.setRenderer(mRender); 109 | } 110 | mTextureProcessor.start(); 111 | } 112 | 113 | public void close(){ 114 | if(mTextureProcessor != null){ 115 | mTextureProcessor.stop(); 116 | } 117 | } 118 | 119 | public void startPreview(){ 120 | if(mShower != null){ 121 | mShower.open(); 122 | } 123 | } 124 | 125 | public void stopPreview(){ 126 | if(mShower != null){ 127 | mShower.close(); 128 | } 129 | } 130 | 131 | /** 132 | * 开始录制 133 | */ 134 | public void startRecord(){ 135 | if(mSurfaceStore != null && mSoundRecord !=null){ 136 | mSurfaceStore.open(); 137 | mSoundRecord.start(); 138 | } 139 | } 140 | 141 | /** 142 | * 关闭录制 143 | */ 144 | public void stopRecord(){ 145 | if(mSoundRecord != null && mSurfaceStore != null && mMuxer != null){ 146 | mSoundRecord.stop(); 147 | mSurfaceStore.close(); 148 | mMuxer.close(); 149 | } 150 | } 151 | 152 | } 153 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/av/VideoCapture.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.av; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.util.SparseArray; 6 | 7 | import com.wuwang.aavt.core.Renderer; 8 | import com.wuwang.aavt.media.video.CameraProvider; 9 | import com.wuwang.aavt.media.video.ITextureProvider; 10 | import com.wuwang.aavt.media.video.Mp4Provider; 11 | import com.wuwang.aavt.media.SurfaceEncoder; 12 | import com.wuwang.aavt.media.SurfaceShower; 13 | import com.wuwang.aavt.media.VideoSurfaceProcessor; 14 | import com.wuwang.aavt.media.hard.IHardStore; 15 | import com.wuwang.aavt.media.hard.StrengthenMp4MuxStore; 16 | 17 | /** 18 | * @author wuwang 19 | * @version 1.00 , 2019/03/13 20 | */ 21 | public class VideoCapture { 22 | 23 | public static final int KEY_CAMERA_MIN_WIDTH = 1; 24 | public static final int KEY_CAMERA_RATE = 2; 25 | public static final int KEY_OUTPUT_WIDTH = 3; 26 | public static final int KEY_OUTPUT_HEIGHT = 4; 27 | public static final int KEY_OUTPUT_PATH = 5; 28 | public static final int KEY_PREVIEW_WIDTH = 6; 29 | public static final int KEY_PREVIEW_HEIGHT = 7; 30 | 31 | private Context context; 32 | private ITextureProvider provider; 33 | private SurfaceShower shower; 34 | private SurfaceEncoder encoder; 35 | private VideoSurfaceProcessor processor; 36 | private IHardStore muxer; 37 | private SparseArray propFloat; 38 | private SparseArray propStr; 39 | private Renderer renderer; 40 | private Object showSurface; 41 | 42 | @SuppressLint("SdCardPath") 43 | private static final String DEFAULT_OUTPUT_PATH = "/mnt/sdcard/test.mp4"; 44 | 45 | public VideoCapture(Context context){ 46 | this.context = context; 47 | propFloat = new SparseArray<>(); 48 | propStr = new SparseArray<>(); 49 | } 50 | 51 | public void setRenderer(Renderer renderer){ 52 | this.renderer = renderer; 53 | if(processor != null){ 54 | processor.setRenderer(renderer); 55 | } 56 | } 57 | 58 | public void setProperty(int key,float value){ 59 | propFloat.put(key,value); 60 | } 61 | 62 | public void setProperty(int key,String value){ 63 | propStr.put(key,value); 64 | } 65 | 66 | @SuppressLint("SdCardPath") 67 | public void open(int id){ 68 | provider = new CameraProvider(); 69 | ((CameraProvider) provider).setDefaultCamera(id); 70 | ((CameraProvider) provider).setCameraSize((int)(float)(propFloat.get(KEY_CAMERA_MIN_WIDTH,720f)),propFloat.get(KEY_CAMERA_RATE,1.7f)); 71 | 72 | shower = new SurfaceShower(); 73 | shower.setOutputSize((int)(float)(propFloat.get(KEY_PREVIEW_WIDTH,720.0f)), 74 | (int)(float)(propFloat.get(KEY_PREVIEW_HEIGHT,1280.0f))); 75 | 76 | muxer = new StrengthenMp4MuxStore(false); 77 | muxer.setOutputPath(propStr.get(KEY_OUTPUT_PATH,DEFAULT_OUTPUT_PATH)); 78 | 79 | encoder = new SurfaceEncoder(); 80 | encoder.setStore(muxer); 81 | encoder.setOutputSize((int)(float)(propFloat.get(KEY_OUTPUT_WIDTH,368.0f)), 82 | (int)(float)(propFloat.get(KEY_OUTPUT_HEIGHT,640.f))); 83 | 84 | processor = new VideoSurfaceProcessor(); 85 | processor.setTextureProvider(provider); 86 | processor.addObserver(shower); 87 | processor.addObserver(encoder); 88 | setRenderer(renderer); 89 | 90 | processor.start(); 91 | } 92 | 93 | public void open(String path){ 94 | muxer = new StrengthenMp4MuxStore(false); 95 | muxer.setOutputPath(propStr.get(KEY_OUTPUT_PATH,DEFAULT_OUTPUT_PATH)); 96 | 97 | provider = new Mp4Provider(); 98 | ((Mp4Provider) provider).setInputPath(path); 99 | ((Mp4Provider) provider).setStore(muxer); 100 | 101 | shower = new SurfaceShower(); 102 | shower.setOutputSize((int)(float)(propFloat.get(KEY_OUTPUT_WIDTH,720.0f)), 103 | (int)(float)(propFloat.get(KEY_OUTPUT_HEIGHT,1280.0f))); 104 | 105 | encoder = new SurfaceEncoder(); 106 | encoder.setStore(muxer); 107 | encoder.setOutputSize((int)(float)(propFloat.get(KEY_OUTPUT_WIDTH,368.0f)), 108 | (int)(float)(propFloat.get(KEY_OUTPUT_HEIGHT,640.f))); 109 | 110 | processor = new VideoSurfaceProcessor(); 111 | processor.setTextureProvider(provider); 112 | processor.addObserver(shower); 113 | processor.addObserver(encoder); 114 | setRenderer(renderer); 115 | 116 | processor.start(); 117 | } 118 | 119 | public void setPreviewSurface(Object surface){ 120 | this.showSurface = surface; 121 | if(shower != null){ 122 | shower.setSurface(surface); 123 | } 124 | } 125 | 126 | public void startPreview(){ 127 | setPreviewSurface(showSurface); 128 | shower.open(); 129 | } 130 | 131 | public void stopPreview(){ 132 | shower.close(); 133 | } 134 | 135 | public void startRecord(){ 136 | encoder.open(); 137 | } 138 | 139 | public void stopRecord(){ 140 | encoder.close(); 141 | muxer.close(); 142 | } 143 | 144 | 145 | public void close(){ 146 | processor.stop(); 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/core/IObservable.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.core; 2 | 3 | /** 4 | * Created by wuwang on 2017/10/20. 5 | */ 6 | 7 | public interface IObservable { 8 | 9 | void addObserver(IObserver observer); 10 | 11 | void notify(Type type); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/core/IObserver.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.core; 2 | 3 | /** 4 | * Created by wuwang on 2017/10/20. 5 | */ 6 | 7 | public interface IObserver { 8 | 9 | void onCall(Type type); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/core/Observable.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.core; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Observer; 5 | 6 | /* 7 | * Created by Wuwang on 2017/10/23 8 | */ 9 | public class Observable implements IObservable { 10 | 11 | private ArrayList> temp; 12 | 13 | @Override 14 | public void addObserver(IObserver observer) { 15 | if(temp==null){ 16 | temp=new ArrayList<>(); 17 | } 18 | temp.add(observer); 19 | } 20 | 21 | public void clear(){ 22 | if(temp!=null){ 23 | temp.clear(); 24 | temp=null; 25 | } 26 | } 27 | 28 | @Override 29 | public void notify(Type type) { 30 | for (IObserver t:temp){ 31 | t.onCall(type); 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/core/Renderer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.core; 15 | 16 | /** 17 | * Renderer 渲染接口,渲染的四个接口应该在同一个GL线程中调用 18 | * 19 | * @author wuwang 20 | * @version v1.0 2017:10:31 11:40 21 | */ 22 | public interface Renderer { 23 | 24 | /** 25 | * 创建 26 | */ 27 | void create(); 28 | 29 | /** 30 | * 大小改变 31 | * @param width 宽度 32 | * @param height 高度 33 | */ 34 | void sizeChanged(int width, int height); 35 | 36 | /** 37 | * 渲染 38 | * @param texture 输入纹理 39 | */ 40 | void draw(int texture); 41 | 42 | /** 43 | * 销毁 44 | */ 45 | void destroy(); 46 | 47 | } 48 | 49 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/egl/EGLConfigAttrs.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.egl; 2 | 3 | import android.opengl.EGL14; 4 | 5 | import java.util.Arrays; 6 | 7 | import javax.microedition.khronos.egl.EGL10; 8 | 9 | /* 10 | * Created by Wuwang on 2017/10/18 11 | */ 12 | public class EGLConfigAttrs { 13 | 14 | private int red=8; 15 | private int green=8; 16 | private int blue=8; 17 | private int alpha=8; 18 | private int depth=8; 19 | private int renderType=4; 20 | private int surfaceType= EGL10.EGL_WINDOW_BIT; 21 | 22 | private boolean makeDefault=false; 23 | 24 | public EGLConfigAttrs red(int red){ 25 | this.red=red; 26 | return this; 27 | } 28 | 29 | public EGLConfigAttrs green(int green){ 30 | this.green=green; 31 | return this; 32 | } 33 | 34 | public EGLConfigAttrs blue(int blue){ 35 | this.blue=blue; 36 | return this; 37 | } 38 | 39 | public EGLConfigAttrs alpha(int alpha){ 40 | this.alpha=alpha; 41 | return this; 42 | } 43 | 44 | public EGLConfigAttrs depth(int depth){ 45 | this.depth=depth; 46 | return this; 47 | } 48 | 49 | public EGLConfigAttrs renderType(int type){ 50 | this.renderType=type; 51 | return this; 52 | } 53 | 54 | public EGLConfigAttrs surfaceType(int type){ 55 | this.surfaceType=type; 56 | return this; 57 | } 58 | 59 | public EGLConfigAttrs makeDefault(boolean def){ 60 | this.makeDefault=def; 61 | return this; 62 | } 63 | 64 | public boolean isDefault(){ 65 | return makeDefault; 66 | } 67 | 68 | int[] build(){ 69 | return new int[] { 70 | EGL10.EGL_SURFACE_TYPE, surfaceType, //渲染类型 71 | EGL10.EGL_RED_SIZE, red, //指定RGB中的R大小(bits) 72 | EGL10.EGL_GREEN_SIZE, green, //指定G大小 73 | EGL10.EGL_BLUE_SIZE, blue, //指定B大小 74 | EGL10.EGL_ALPHA_SIZE, alpha, //指定Alpha大小,以上四项实际上指定了像素格式 75 | EGL10.EGL_DEPTH_SIZE, depth, //指定深度缓存(Z Buffer)大小 76 | EGL10.EGL_RENDERABLE_TYPE, renderType, //指定渲染api类别, 如上一小节描述,这里或者是硬编码的4(EGL14.EGL_OPENGL_ES2_BIT) 77 | EGL10.EGL_NONE }; //总是以EGL14.EGL_NONE结尾 78 | } 79 | 80 | @Override 81 | public String toString() { 82 | return Arrays.toString(build()); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/egl/EGLContextAttrs.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.egl; 2 | 3 | import javax.microedition.khronos.egl.EGL10; 4 | 5 | /* 6 | * Created by Wuwang on 2017/10/18 7 | */ 8 | public class EGLContextAttrs { 9 | 10 | private int version=2; 11 | 12 | private boolean isDefault; 13 | 14 | public EGLContextAttrs version(int v){ 15 | this.version=v; 16 | return this; 17 | } 18 | 19 | public EGLContextAttrs makeDefault(boolean def){ 20 | this.isDefault=def; 21 | return this; 22 | } 23 | 24 | public boolean isDefault(){ 25 | return isDefault; 26 | } 27 | 28 | int[] build(){ 29 | return new int[]{0x3098,version, EGL10.EGL_NONE}; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/expend/SluggardFilterTool.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.expend; 15 | 16 | import com.wuwang.aavt.gl.BaseFilter; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | 20 | /** 21 | * SluggardFilterTool 懒汉Filter工具,该工具用于快速使用{@link BaseFilter}及其子类来处理纹理,而无需关注框架中 22 | * 的滤镜处理流程。通常情况下,不推荐使用此工具类,推荐尽可能熟悉框架中的滤镜处理流程。然后自行根据业务逻辑, 23 | * 参照此类进行封装。 24 | * 25 | * @author wuwang 26 | * @version v1.0 2017:11:11 15:41 27 | */ 28 | public class SluggardFilterTool { 29 | 30 | private long threadId=-1; 31 | private HashMap filters=new HashMap<>(); 32 | 33 | /** 34 | * 处理一个纹理,并输出处理后的纹理 35 | * @param texture 输入纹理 36 | * @param width 输出纹理宽度 37 | * @param height 输出纹理高度 38 | * @param clazz 滤镜类型 39 | * @return 输出纹理 40 | */ 41 | public int processTexture(int texture, int width, int height, Class clazz){ 42 | long nowThreadId=Thread.currentThread().getId(); 43 | if(nowThreadId!=threadId){ 44 | filters.clear(); 45 | threadId=nowThreadId; 46 | } 47 | BaseFilter filter=filters.get(clazz); 48 | if(filter==null){ 49 | try { 50 | filter=clazz.newInstance(); 51 | filter.create(); 52 | } catch (InstantiationException e) { 53 | e.printStackTrace(); 54 | } catch (IllegalAccessException e) { 55 | e.printStackTrace(); 56 | } 57 | filters.put(clazz,filter); 58 | } 59 | if(filter!=null){ 60 | filter.sizeChanged(width, height); 61 | return filter.drawToTexture(texture); 62 | } 63 | return -1; 64 | } 65 | 66 | /** 67 | * 处理一个纹理,并输出处理后的纹理 68 | * @param texture 输入纹理 69 | * @param width 输出纹理宽度 70 | * @param height 输出纹理高度 71 | * @param filter 滤镜实体 72 | * @return 输出纹理 73 | */ 74 | public int processTexture(int texture,int width,int height,BaseFilter filter){ 75 | long nowThreadId=Thread.currentThread().getId(); 76 | if(nowThreadId!=threadId){ 77 | filters.clear(); 78 | threadId=nowThreadId; 79 | } 80 | if(filter!=null){ 81 | Class clazz=filter.getClass(); 82 | if(filters.get(clazz)==null){ 83 | filters.put(clazz,filter); 84 | filter.create(); 85 | } 86 | filter.sizeChanged(width, height); 87 | return filter.drawToTexture(texture); 88 | } 89 | return -1; 90 | } 91 | 92 | public void onGlDestroy(){ 93 | for (Map.Entry classBaseFilterEntry : filters.entrySet()) { 94 | BaseFilter filter = classBaseFilterEntry.getValue(); 95 | filter.destroy(); 96 | } 97 | filters.clear(); 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/gl/BaseFuncFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.gl; 15 | 16 | import android.content.res.Resources; 17 | 18 | /** 19 | * BaseFuncFilter 基础功能滤镜 20 | * 21 | * @author wuwang 22 | * @version v1.0 2017:10:31 11:47 23 | */ 24 | class BaseFuncFilter extends BaseFilter { 25 | 26 | static final String FILTER_SOBEL="shader/func/sobel.frag"; 27 | static final String FILTER_SOBEL_REVERSE="shader/func/sobel2.frag"; 28 | static final String FILTER_GAUSS="shader/func/gauss.frag"; 29 | 30 | BaseFuncFilter(Resources resource, String fragment) { 31 | super(resource, "shader/base.vert", fragment); 32 | shaderNeedTextureSize(true); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/gl/BeautyFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.gl; 15 | 16 | import android.content.res.Resources; 17 | import android.opengl.GLES20; 18 | 19 | /** 20 | * BeautyFilter 美颜滤镜 21 | * 22 | * @author wuwang 23 | * @version v1.0 2017:10:31 11:46 24 | */ 25 | public class BeautyFilter extends BaseFilter { 26 | 27 | private int mGLaaCoef; 28 | private int mGLmixCoef; 29 | private int mGLiternum; 30 | 31 | 32 | private float aaCoef; 33 | private float mixCoef; 34 | private int iternum; 35 | 36 | public BeautyFilter(Resources resource) { 37 | super(resource,"shader/beauty/beauty.vert", "shader/beauty/beauty.frag"); 38 | shaderNeedTextureSize(true); 39 | setBeautyLevel(0); 40 | } 41 | 42 | @Override 43 | protected void onCreate() { 44 | super.onCreate(); 45 | mGLaaCoef= GLES20.glGetUniformLocation(mGLProgram,"uACoef"); 46 | mGLmixCoef=GLES20.glGetUniformLocation(mGLProgram,"uMixCoef"); 47 | mGLiternum=GLES20.glGetUniformLocation(mGLProgram,"uIternum"); 48 | } 49 | 50 | public BaseFilter setBeautyLevel(int level){ 51 | switch (level){ 52 | case 1: 53 | a(1,0.19f,0.54f); 54 | break; 55 | case 2: 56 | a(2,0.29f,0.54f); 57 | break; 58 | case 3: 59 | a(3,0.17f,0.39f); 60 | break; 61 | case 4: 62 | a(3,0.25f,0.54f); 63 | break; 64 | case 5: 65 | a(4,0.13f,0.54f); 66 | break; 67 | case 6: 68 | a(4,0.19f,0.69f); 69 | break; 70 | default: 71 | a(0,0f,0f); 72 | break; 73 | } 74 | return this; 75 | } 76 | 77 | private void a(final int a, final float b, final float c){ 78 | runOnGLThread(new Runnable() { 79 | @Override 80 | public void run() { 81 | GLES20.glUniform1f(mGLaaCoef,b); 82 | GLES20.glUniform1f(mGLmixCoef,c); 83 | GLES20.glUniform1i(mGLiternum,a); 84 | } 85 | }); 86 | } 87 | 88 | } 89 | 90 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/gl/BlackMagicFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.gl; 15 | 16 | import android.content.res.Resources; 17 | 18 | /** 19 | * BlackMagicFilter 黑魔法滤镜,sobel算法实现 20 | * 21 | * @author wuwang 22 | * @version v1.0 2017:10:31 11:47 23 | */ 24 | public class BlackMagicFilter extends GroupFilter { 25 | 26 | public BlackMagicFilter(Resources resources){ 27 | super(resources); 28 | } 29 | 30 | @Override 31 | protected void initBuffer() { 32 | super.initBuffer(); 33 | addFilter(new GrayFilter(mRes)); 34 | addFilter(new BaseFuncFilter(mRes,BaseFuncFilter.FILTER_SOBEL)); 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/gl/CandyFilter.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.gl; 2 | 3 | import android.content.res.Resources; 4 | 5 | /** 6 | * Created by 15581 on 2017/9/30. 7 | */ 8 | 9 | public class CandyFilter extends GroupFilter { 10 | 11 | public CandyFilter(Resources resource) { 12 | super(resource); 13 | } 14 | 15 | @Override 16 | protected void initBuffer() { 17 | super.initBuffer(); 18 | addFilter(new GrayFilter(mRes)); 19 | addFilter(new BaseFuncFilter(mRes,BaseFuncFilter.FILTER_GAUSS)); 20 | addFilter(new BaseFuncFilter(mRes,BaseFuncFilter.FILTER_SOBEL)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/gl/Faltung3x3Filter.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.gl; 2 | 3 | import android.content.res.Resources; 4 | import android.opengl.GLES20; 5 | 6 | /** 7 | * Created by wuwang on 2017/10/1. 8 | */ 9 | 10 | public class Faltung3x3Filter extends BaseFilter { 11 | 12 | private float[] mFaltung; 13 | private int mGLFaltung; 14 | 15 | public static final float[] FILTER_SHARPEN=new float[]{0,-1,0,-1,5,-1,0,-1,0}; 16 | public static final float[] FILTER_BORDER=new float[]{0,1,0,1,-4,1,0,1,0}; 17 | public static final float[] FILTER_CAMEO=new float[]{2,0,2,0,0,0,3,0,-6}; 18 | 19 | public Faltung3x3Filter(Resources res,float[] faltung){ 20 | super(res,"shader/base.vert","shader/func/faltung3x3.frag"); 21 | shaderNeedTextureSize(true); 22 | this.mFaltung=faltung; 23 | } 24 | 25 | @Override 26 | protected void onCreate() { 27 | super.onCreate(); 28 | mGLFaltung= GLES20.glGetUniformLocation(mGLProgram,"uFaltung"); 29 | } 30 | 31 | @Override 32 | protected void onSetExpandData() { 33 | super.onSetExpandData(); 34 | GLES20.glUniformMatrix3fv(mGLFaltung,1,false,mFaltung,0); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/gl/FluorescenceFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.gl; 15 | 16 | import android.content.res.Resources; 17 | import android.opengl.GLES20; 18 | 19 | /** 20 | * FluorescenceFilter 荧光滤镜 21 | * 22 | * @author wuwang 23 | * @version v1.0 2017:10:31 11:50 24 | */ 25 | public class FluorescenceFilter extends BaseFilter { 26 | 27 | private int mGLTexture2; 28 | private int mGLBorderColor; 29 | private int mGLStep; 30 | private BlackMagicFilter mBlackFilter; 31 | private int mTempTexture; 32 | private float[] mBorderColor=new float[]{0f,1f,1f,1}; 33 | private float mStep=1.0f; 34 | 35 | private boolean isAdd=true; 36 | 37 | public FluorescenceFilter(Resources resource) { 38 | super(resource, "shader/base.vert", "shader/effect/fluorescence.frag"); 39 | shaderNeedTextureSize(true); 40 | mBlackFilter=new BlackMagicFilter(resource); 41 | } 42 | 43 | @Override 44 | protected void onCreate() { 45 | mBlackFilter.create(); 46 | super.onCreate(); 47 | mGLTexture2= GLES20.glGetUniformLocation(mGLProgram,"uTexture2"); 48 | mGLBorderColor= GLES20.glGetUniformLocation(mGLProgram,"uBorderColor"); 49 | mGLStep=GLES20.glGetUniformLocation(mGLProgram,"uStep"); 50 | } 51 | 52 | @Override 53 | protected void onSizeChanged(int width, int height) { 54 | super.onSizeChanged(width, height); 55 | mBlackFilter.sizeChanged(width, height); 56 | } 57 | 58 | @Override 59 | public void draw(int texture) { 60 | mTempTexture=mBlackFilter.drawToTexture(texture); 61 | super.draw(texture); 62 | } 63 | 64 | @Override 65 | protected void onBindTexture(int textureId) { 66 | super.onBindTexture(textureId); 67 | GLES20.glActiveTexture(GLES20.GL_TEXTURE1); 68 | GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,mTempTexture); 69 | GLES20.glUniform1i(mGLTexture2,1); 70 | } 71 | 72 | @Override 73 | protected void onSetExpandData() { 74 | //todo 根据时间修改 75 | 76 | if(isAdd){ 77 | mStep+=0.08f; 78 | }else{ 79 | mStep-=0.08f; 80 | } 81 | 82 | if(mStep>=1.0f){ 83 | isAdd=false; 84 | mStep=1.0f; 85 | }else if(mStep<=0.0f){ 86 | isAdd=true; 87 | mStep=0.0f; 88 | } 89 | 90 | super.onSetExpandData(); 91 | GLES20.glUniform4fv(mGLBorderColor,1,mBorderColor,0); 92 | GLES20.glUniform1f(mGLStep,mStep); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/gl/GrayFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.gl; 15 | 16 | import android.content.res.Resources; 17 | 18 | /** 19 | * GrayFilter 灰度滤镜 20 | * 21 | * @author wuwang 22 | * @version v1.0 2017:10:31 11:52 23 | */ 24 | public class GrayFilter extends BaseFilter { 25 | 26 | public GrayFilter(Resources resource) { 27 | super(resource, "shader/base.vert", "shader/color/gray.frag"); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/gl/GroupFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.gl; 15 | 16 | import android.content.res.Resources; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Iterator; 20 | import java.util.Vector; 21 | 22 | /** 23 | * GroupFilter 滤镜组,将多个滤镜串联起来,合并成一个滤镜 24 | * 25 | * @author wuwang 26 | * @version v1.0 2017:10:31 11:53 27 | */ 28 | public class GroupFilter extends LazyFilter { 29 | 30 | private ArrayList mGroup; 31 | 32 | public GroupFilter(Resources resource) { 33 | super(resource); 34 | } 35 | 36 | public GroupFilter(){ 37 | super(); 38 | } 39 | 40 | @Override 41 | protected void initBuffer() { 42 | super.initBuffer(); 43 | mGroup=new ArrayList<>(); 44 | } 45 | 46 | public void addFilter(final BaseFilter filter){ 47 | runOnGLThread(new Runnable() { 48 | @Override 49 | public void run() { 50 | filter.create(); 51 | filter.sizeChanged(mWidth,mHeight); 52 | mGroup.add(filter); 53 | } 54 | }); 55 | } 56 | 57 | public void addFilter(final int index,final BaseFilter filter){ 58 | runOnGLThread(new Runnable() { 59 | @Override 60 | public void run() { 61 | filter.create(); 62 | filter.sizeChanged(mWidth,mHeight); 63 | mGroup.add(index, filter); 64 | } 65 | }); 66 | } 67 | 68 | public BaseFilter removeFilter(final int index){ 69 | BaseFilter filter=mGroup.get(index); 70 | runOnGLThread(new Runnable() { 71 | @Override 72 | public void run() { 73 | BaseFilter filter=mGroup.remove(index); 74 | if(filter!=null){ 75 | filter.destroy(); 76 | } 77 | } 78 | }); 79 | return filter; 80 | } 81 | 82 | public void removeFilter(final BaseFilter filter){ 83 | runOnGLThread(new Runnable() { 84 | @Override 85 | public void run() { 86 | mGroup.remove(filter); 87 | } 88 | }); 89 | } 90 | 91 | public BaseFilter get(int index){ 92 | return mGroup.get(index); 93 | } 94 | 95 | public Iterator iterator(){ 96 | return mGroup.iterator(); 97 | } 98 | 99 | public boolean isEmpty(){ 100 | return mGroup.isEmpty(); 101 | } 102 | 103 | @Override 104 | public void draw(int texture) { 105 | int tempTextureId=texture; 106 | for (int i=0;i=(mXRollTime+mYRollTime)){ 54 | mFrameCount=0; 55 | } 56 | if(mFrameCount= Build.VERSION_CODES.LOLLIPOP) { 32 | return codec.getInputBuffer(index); 33 | }else{ 34 | return codec.getInputBuffers()[index]; 35 | } 36 | } 37 | 38 | public static ByteBuffer getOutputBuffer(MediaCodec codec, int index){ 39 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 40 | return codec.getOutputBuffer(index); 41 | }else{ 42 | return codec.getOutputBuffers()[index]; 43 | } 44 | } 45 | 46 | } 47 | 48 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/MediaConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.media; 15 | 16 | /** 17 | * MediaConfig 音视频编码信息设置 18 | * 19 | * @author wuwang 20 | * @version v1.0 2017:10:26 18:28 21 | */ 22 | public class MediaConfig { 23 | 24 | public Video mVideo=new Video(); 25 | public Audio mAudio=new Audio(); 26 | 27 | public class Video{ 28 | public String mime="video/avc"; 29 | public int width=368; 30 | public int height=640; 31 | public int frameRate=24; 32 | public int iframe=1; 33 | public int bitrate=1177600; 34 | public int colorFormat; 35 | } 36 | 37 | public class Audio{ 38 | public String mime="audio/mp4a-latm"; 39 | public int sampleRate=48000; 40 | public int channelCount=2; 41 | public int bitrate=128000; 42 | public int profile; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/RenderBean.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.media; 15 | 16 | import com.wuwang.aavt.egl.EglHelper; 17 | 18 | /** 19 | * RenderBean 20 | * 21 | * @author wuwang 22 | * @version v1.0 2017:10:27 15:02 23 | */ 24 | public class RenderBean { 25 | 26 | public EglHelper egl; 27 | public int sourceWidth; 28 | public int sourceHeight; 29 | public int textureId; 30 | public boolean endFlag; 31 | 32 | public long timeStamp; 33 | public long textureTime; 34 | 35 | public long threadId; 36 | 37 | } 38 | 39 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/SurfaceShower.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.media; 15 | 16 | import android.opengl.EGLSurface; 17 | import android.opengl.GLES20; 18 | 19 | import com.wuwang.aavt.core.IObserver; 20 | import com.wuwang.aavt.gl.BaseFilter; 21 | import com.wuwang.aavt.gl.LazyFilter; 22 | import com.wuwang.aavt.utils.MatrixUtils; 23 | 24 | /** 25 | * SurfaceShower 用于将RenderBean展示到指定的Surface上 26 | * 27 | * @author wuwang 28 | * @version v1.0 2017:10:27 08:53 29 | */ 30 | public class SurfaceShower implements IObserver { 31 | 32 | private EGLSurface mShowSurface; 33 | private boolean isShow=false; 34 | private BaseFilter mFilter; 35 | private Object mSurface; 36 | private int mWidth; 37 | private int mHeight; 38 | private int mMatrixType= MatrixUtils.TYPE_CENTERCROP; 39 | private OnDrawEndListener mListener; 40 | private RenderBean mBean; 41 | 42 | public void setOutputSize(int width,int height){ 43 | this.mWidth=width; 44 | this.mHeight=height; 45 | } 46 | 47 | private void clearSurface() { 48 | if(mShowSurface!=null){ 49 | mBean.egl.destroySurface(mShowSurface); 50 | mShowSurface = null; 51 | } 52 | } 53 | 54 | /** 55 | * 设置输出的Surface 56 | * @param surface {@link android.view.Surface}、{@link android.graphics.SurfaceTexture}或{@link android.view.TextureView} 57 | */ 58 | public void setSurface(Object surface){ 59 | this.mSurface=surface; 60 | clearSurface(); 61 | } 62 | 63 | /** 64 | * 设置矩阵变换类型 65 | * @param type 变换类型,{@link MatrixUtils#TYPE_FITXY},{@link MatrixUtils#TYPE_FITSTART},{@link MatrixUtils#TYPE_CENTERCROP},{@link MatrixUtils#TYPE_CENTERINSIDE}或{@link MatrixUtils#TYPE_FITEND} 66 | */ 67 | public void setMatrixType(int type){ 68 | this.mMatrixType=type; 69 | } 70 | 71 | public void open(){ 72 | isShow=true; 73 | } 74 | 75 | public void close(){ 76 | isShow=false; 77 | } 78 | 79 | @Override 80 | public void onCall(RenderBean rb) { 81 | if(rb.endFlag){ 82 | clearSurface(); 83 | }else if(isShow&&mSurface!=null){ 84 | if(mShowSurface==null){ 85 | mBean = rb; 86 | mShowSurface=rb.egl.createWindowSurface(mSurface); 87 | mFilter=new LazyFilter(); 88 | mFilter.create(); 89 | mFilter.sizeChanged(rb.sourceWidth, rb.sourceHeight); 90 | MatrixUtils.getMatrix(mFilter.getVertexMatrix(),mMatrixType,rb.sourceWidth,rb.sourceHeight, 91 | mWidth,mHeight); 92 | MatrixUtils.flip(mFilter.getVertexMatrix(),false,true); 93 | } 94 | rb.egl.makeCurrent(mShowSurface); 95 | GLES20.glViewport(0,0,mWidth,mHeight); 96 | mFilter.draw(rb.textureId); 97 | if(mListener!=null){ 98 | mListener.onDrawEnd(mShowSurface,rb); 99 | } 100 | rb.egl.swapBuffers(mShowSurface); 101 | } 102 | } 103 | 104 | /** 105 | * 设置单帧渲染完成监听器 106 | * @param listener 监听器 107 | */ 108 | public void setOnDrawEndListener(OnDrawEndListener listener){ 109 | this.mListener=listener; 110 | } 111 | 112 | public interface OnDrawEndListener{ 113 | /** 114 | * 渲染完成通知 115 | * @param surface 渲染的目标EGLSurface 116 | * @param bean 渲染用的资源 117 | */ 118 | void onDrawEnd(EGLSurface surface,RenderBean bean); 119 | } 120 | 121 | } 122 | 123 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/WrapRenderer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.media; 15 | 16 | import com.wuwang.aavt.core.Renderer; 17 | import com.wuwang.aavt.gl.OesFilter; 18 | import com.wuwang.aavt.utils.MatrixUtils; 19 | 20 | 21 | /** 22 | * WrapRenderer 用于包装其他Filter渲染OES纹理 23 | * 24 | * @author wuwang 25 | * @version v1.0 2017:10:27 08:53 26 | */ 27 | public class WrapRenderer implements Renderer { 28 | 29 | private Renderer mRenderer; 30 | private OesFilter mFilter; 31 | 32 | public static final int TYPE_MOVE=0; 33 | public static final int TYPE_CAMERA=1; 34 | 35 | public WrapRenderer(Renderer renderer){ 36 | this.mRenderer=renderer; 37 | mFilter=new OesFilter(); 38 | setFlag(TYPE_MOVE); 39 | } 40 | 41 | public void setFlag(int flag){ 42 | if(flag==TYPE_MOVE){ 43 | mFilter.setVertexCo(new float[]{ 44 | -1.0f,1.0f, 45 | -1.0f,-1.0f, 46 | 1.0f,1.0f, 47 | 1.0f,-1.0f, 48 | }); 49 | }else if(flag==TYPE_CAMERA){ 50 | mFilter.setVertexCo(new float[]{ 51 | -1.0f, -1.0f, 52 | 1.0f, -1.0f, 53 | -1.0f, 1.0f, 54 | 1.0f, 1.0f, 55 | }); 56 | } 57 | } 58 | 59 | public float[] getTextureMatrix(){ 60 | return mFilter.getTextureMatrix(); 61 | } 62 | 63 | @Override 64 | public void create() { 65 | mFilter.create(); 66 | if(mRenderer!=null){ 67 | mRenderer.create(); 68 | } 69 | } 70 | 71 | @Override 72 | public void sizeChanged(int width, int height) { 73 | mFilter.sizeChanged(width, height); 74 | if(mRenderer!=null){ 75 | mRenderer.sizeChanged(width, height); 76 | } 77 | } 78 | 79 | @Override 80 | public void draw(int texture) { 81 | if(mRenderer!=null){ 82 | mRenderer.draw(mFilter.drawToTexture(texture)); 83 | }else{ 84 | mFilter.draw(texture); 85 | } 86 | } 87 | 88 | @Override 89 | public void destroy() { 90 | if(mRenderer!=null){ 91 | mRenderer.destroy(); 92 | } 93 | mFilter.destroy(); 94 | } 95 | } 96 | 97 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/audio/FileAudioProvider.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.media.audio; 2 | 3 | import android.annotation.TargetApi; 4 | import android.media.MediaCodec; 5 | import android.media.MediaExtractor; 6 | import android.media.MediaFormat; 7 | import android.os.Build; 8 | import android.support.annotation.NonNull; 9 | import android.support.annotation.RequiresApi; 10 | 11 | import com.wuwang.aavt.media.CodecUtil; 12 | 13 | import java.io.IOException; 14 | import java.nio.ByteBuffer; 15 | 16 | /** 17 | * @author wuwang 18 | * @version 1.00 , 2019/03/13 19 | */ 20 | 21 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 22 | public class FileAudioProvider extends MediaCodec.Callback implements ISoundProvider { 23 | 24 | private MediaExtractor extractor; 25 | private MediaCodec codec; 26 | private int audioTrack = -1; 27 | private MediaFormat format; 28 | private final long TIME_US = 1000; 29 | 30 | private FileAudioProvider(){} 31 | 32 | @Override 33 | public void onInputBufferAvailable(@NonNull MediaCodec codec, int index) { 34 | ByteBuffer buffer = CodecUtil.getInputBuffer(codec,index); 35 | buffer.clear(); 36 | int size = extractor.readSampleData(buffer,0); 37 | codec.queueInputBuffer(index,0,size ,extractor.getSampleTime(),extractor.getSampleFlags()); 38 | } 39 | 40 | @Override 41 | public void onOutputBufferAvailable(@NonNull MediaCodec codec, int index, @NonNull MediaCodec.BufferInfo info) { 42 | ByteBuffer buffer = CodecUtil.getOutputBuffer(codec,index); 43 | codec.releaseOutputBuffer(index,false); 44 | } 45 | 46 | @Override 47 | public void onError(@NonNull MediaCodec codec, @NonNull MediaCodec.CodecException e) { 48 | 49 | } 50 | 51 | @Override 52 | public void onOutputFormatChanged(@NonNull MediaCodec codec, @NonNull MediaFormat format) { 53 | 54 | } 55 | 56 | private boolean setPath(String path){ 57 | try { 58 | extractor = new MediaExtractor(); 59 | extractor.setDataSource(path); 60 | int count = extractor.getTrackCount(); 61 | if(count <= 0){ 62 | return false; 63 | } 64 | for (int i=0;i=0){ 96 | ByteBuffer buffer = CodecUtil.getInputBuffer(codec,inputId); 97 | buffer.clear(); 98 | 99 | } 100 | } 101 | 102 | @Override 103 | public void close() { 104 | codec.stop(); 105 | codec.release(); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/audio/ISoundProvider.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.media.audio; 2 | 3 | import com.wuwang.aavt.media.av.ICloseable; 4 | 5 | /** 6 | * @author wuwang 7 | * @version 1.00 , 2019/03/13 8 | */ 9 | public interface ISoundProvider extends ICloseable { 10 | 11 | void open(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/audio/MicAudioProvider.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.media.audio; 2 | 3 | import android.media.AudioFormat; 4 | import android.media.AudioRecord; 5 | import android.media.MediaRecorder; 6 | 7 | import com.wuwang.aavt.media.audio.ISoundProvider; 8 | import com.wuwang.aavt.media.av.AvException; 9 | 10 | /** 11 | * @author wuwang 12 | * @version 1.00 , 2019/03/13 13 | */ 14 | public class MicAudioProvider implements ISoundProvider { 15 | 16 | private AudioRecord record; 17 | private int recordBufferSize=0; 18 | private int sampleRateInHz=48000; //音频采样率 19 | private int channelConfig= AudioFormat.CHANNEL_IN_STEREO; //音频录制通道,默认为立体声 20 | private int audioFormat=AudioFormat.ENCODING_PCM_16BIT; //音频录制格式,默认为PCM16Bit 21 | 22 | public MicAudioProvider(){ 23 | setProperty(sampleRateInHz,channelConfig,audioFormat); 24 | } 25 | 26 | public MicAudioProvider(int sampleRateInHz, int channelConfig, int audioFormat){ 27 | setProperty(sampleRateInHz, channelConfig, audioFormat); 28 | } 29 | 30 | public void setProperty(int sampleRateInHz, int channelConfig, int audioFormat){ 31 | this.sampleRateInHz = sampleRateInHz; 32 | this.channelConfig = channelConfig; 33 | this.audioFormat = audioFormat; 34 | this.recordBufferSize = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat) * 2; 35 | } 36 | 37 | @Override 38 | public void open() { 39 | close(); 40 | record = new AudioRecord(MediaRecorder.AudioSource.MIC,sampleRateInHz,channelConfig,audioFormat,recordBufferSize); 41 | record.startRecording(); 42 | } 43 | 44 | @Override 45 | public void close() { 46 | if(record != null){ 47 | record.stop(); 48 | record.release(); 49 | record = null; 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/av/AvException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.media.av; 15 | 16 | /** 17 | * AVException 18 | * 19 | * @author wuwang 20 | * @version v1.0 2017:10:28 17:27 21 | */ 22 | public class AvException extends Exception { 23 | 24 | public AvException(){ 25 | super(); 26 | } 27 | 28 | public AvException(String msg){ 29 | super("AVException:"+msg); 30 | } 31 | 32 | public AvException(String message, Throwable cause) { 33 | super("AVException:"+message, cause); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/av/ICloseable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.media.av; 15 | 16 | /** 17 | * ICloseable 18 | * 19 | * @author wuwang 20 | * @version v1.0 2017:10:28 17:25 21 | */ 22 | public interface ICloseable { 23 | 24 | void close(); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/av/IStore.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.media.av; 15 | 16 | /** 17 | * IStore 文件存储接口 18 | * 19 | * @author wuwang 20 | * @version v1.0 2017:10:28 16:39 21 | */ 22 | public interface IStore extends ICloseable{ 23 | 24 | /** 25 | * 增加存储轨道 26 | * @param track 待存储的内容信息 27 | * @return 轨道索引 28 | */ 29 | int addTrack(Track track); 30 | 31 | /** 32 | * 写入内容到存储中 33 | * @param track 轨道索引 34 | * @param data 存储内容,包括内容信息 35 | * @return 写入结果 36 | */ 37 | int addData(int track,Data data); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/hard/HardMediaData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.media.hard; 15 | 16 | import android.media.MediaCodec; 17 | import android.os.Build; 18 | import android.support.annotation.RequiresApi; 19 | 20 | import java.nio.ByteBuffer; 21 | 22 | /** 23 | * HardMediaData 24 | * 25 | * @author wuwang 26 | * @version v1.0 2017:10:28 16:53 27 | */ 28 | public class HardMediaData { 29 | 30 | public int index=-1; 31 | public ByteBuffer data; 32 | public MediaCodec.BufferInfo info; 33 | 34 | public HardMediaData(ByteBuffer buffer, MediaCodec.BufferInfo info){ 35 | this.data=buffer; 36 | this.info=info; 37 | } 38 | 39 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN) 40 | public void copyTo(HardMediaData data){ 41 | data.index=index; 42 | data.data.position(0); 43 | data.data.put(this.data); 44 | data.info.set(info.offset,info.size,info.presentationTimeUs,info.flags); 45 | } 46 | 47 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN) 48 | public HardMediaData copy(){ 49 | ByteBuffer buffer=ByteBuffer.allocate(data.capacity()); 50 | MediaCodec.BufferInfo info=new MediaCodec.BufferInfo(); 51 | HardMediaData data=new HardMediaData(buffer,info); 52 | copyTo(data); 53 | return data; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/hard/IHardStore.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.media.hard; 15 | 16 | import android.media.MediaFormat; 17 | 18 | import com.wuwang.aavt.media.av.IStore; 19 | 20 | /** 21 | * IHardStore 硬编码的媒体文件存储器 22 | * 23 | * @author wuwang 24 | * @version v1.0 2017:10:28 16:52 25 | */ 26 | public interface IHardStore extends IStore { 27 | 28 | /** 29 | * 设置存储路径 30 | * @param path 路径 31 | */ 32 | void setOutputPath(String path); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/hard/MediaMuxerWraper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.media.hard; 15 | 16 | import android.annotation.TargetApi; 17 | import android.media.MediaCodec; 18 | import android.media.MediaFormat; 19 | import android.media.MediaMuxer; 20 | import android.os.Build; 21 | import android.support.annotation.NonNull; 22 | import android.support.annotation.RequiresApi; 23 | 24 | import com.wuwang.aavt.log.AvLog; 25 | 26 | import java.io.IOException; 27 | import java.nio.ByteBuffer; 28 | import java.util.concurrent.BlockingQueue; 29 | import java.util.concurrent.ExecutorService; 30 | import java.util.concurrent.Executors; 31 | import java.util.concurrent.LinkedBlockingQueue; 32 | import java.util.concurrent.ThreadFactory; 33 | import java.util.concurrent.ThreadPoolExecutor; 34 | import java.util.concurrent.TimeUnit; 35 | 36 | /** 37 | * MediaMuxerWraper 38 | * 39 | * @author wuwang 40 | * @version v1.0 2017:11:08 11:07 41 | */ 42 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) 43 | public class MediaMuxerWraper{ 44 | 45 | private final String tag=getClass().getSimpleName(); 46 | private MediaMuxer mMuxer; 47 | private BlockingQueue datas; 48 | private Recycler recycler; 49 | private boolean isStarted=false; 50 | private int indexCount=0; 51 | private final Object Lock=new Object(); 52 | private ExecutorService mExec; 53 | 54 | public MediaMuxerWraper(String path, int format) throws IOException { 55 | mMuxer=new MediaMuxer(path,format); 56 | datas=new LinkedBlockingQueue<>(30); 57 | recycler=new Recycler<>(); 58 | ThreadFactory factory= Executors.defaultThreadFactory(); 59 | mExec=new ThreadPoolExecutor(1,1,1,TimeUnit.MINUTES,new LinkedBlockingQueue(16),factory); 60 | } 61 | 62 | private void muxRun(){ 63 | while (isStarted){ 64 | try { 65 | HardMediaData data=datas.poll(1, TimeUnit.SECONDS); 66 | AvLog.d(tag,"get HardMediaData from the queue"); 67 | synchronized (Lock){ 68 | if(isStarted){ 69 | mMuxer.writeSampleData(data.index, data.data, data.info); 70 | recycler.put(data.index,data); 71 | } 72 | } 73 | } catch (InterruptedException e) { 74 | e.printStackTrace(); 75 | } 76 | } 77 | AvLog.d(tag,"end -->"); 78 | mMuxer.stop(); 79 | mMuxer.release(); 80 | datas.clear(); 81 | recycler.clear(); 82 | } 83 | 84 | public void release(){ 85 | stop(); 86 | } 87 | 88 | public void start(){ 89 | synchronized (Lock){ 90 | if(!isStarted){ 91 | mMuxer.start(); 92 | isStarted=true; 93 | mExec.execute(new Runnable() { 94 | @Override 95 | public void run() { 96 | muxRun(); 97 | } 98 | }); 99 | } 100 | } 101 | } 102 | 103 | public void stop(){ 104 | synchronized (Lock){ 105 | indexCount=0; 106 | isStarted=false; 107 | } 108 | } 109 | 110 | @RequiresApi(api = Build.VERSION_CODES.KITKAT) 111 | public void setLocation(float latitude, float longitude){ 112 | mMuxer.setLocation(latitude, longitude); 113 | } 114 | 115 | public void writeSampleData(int trackIndex, @NonNull ByteBuffer byteBuf, 116 | @NonNull MediaCodec.BufferInfo bufferInfo){ 117 | HardMediaData hmd=recycler.poll(trackIndex); 118 | if(hmd==null){ 119 | ByteBuffer buffer=ByteBuffer.allocate(byteBuf.capacity()); 120 | MediaCodec.BufferInfo info=new MediaCodec.BufferInfo(); 121 | hmd=new HardMediaData(buffer,info); 122 | AvLog.d(tag,"buffer Size->"+buffer.capacity()); 123 | } 124 | AvLog.i(tag,"buffer Size->"+hmd.data.capacity()+"/data size:"+bufferInfo.size); 125 | hmd.data.position(0); 126 | hmd.data.put(byteBuf); 127 | hmd.info.set(bufferInfo.offset,bufferInfo.size,bufferInfo.presentationTimeUs,bufferInfo.flags); 128 | hmd.index=trackIndex; 129 | datas.offer(hmd); 130 | } 131 | 132 | public int addTrack(@NonNull MediaFormat format){ 133 | indexCount++; 134 | AvLog.d(tag,"addTrack -->"+indexCount); 135 | return mMuxer.addTrack(format); 136 | } 137 | 138 | public void setOrientationHint(int degrees){ 139 | mMuxer.setOrientationHint(degrees); 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/hard/Mp4MuxStore.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.media.hard; 15 | 16 | import android.annotation.TargetApi; 17 | import android.media.MediaFormat; 18 | import android.media.MediaMuxer; 19 | import android.os.Build; 20 | import android.util.Log; 21 | 22 | import com.wuwang.aavt.media.av.AvException; 23 | 24 | import java.io.IOException; 25 | 26 | /** 27 | * Mp4MuxStore 28 | * 29 | * @author wuwang 30 | * @version v1.0 2017:10:28 17:48 31 | */ 32 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) 33 | public class Mp4MuxStore implements IHardStore { 34 | 35 | private MediaMuxer mMuxer; 36 | private final Object LOCK=new Object(); 37 | private String mPath; 38 | private int mAudioTrack=-1; 39 | private int mVideoTrack=-1; 40 | private boolean isMuxStart=false; 41 | private boolean waiAudio=true; 42 | 43 | public Mp4MuxStore(boolean waitAudio){ 44 | this.waiAudio=waitAudio; 45 | } 46 | 47 | @Override 48 | public int addTrack(MediaFormat mediaFormat) { 49 | synchronized (LOCK){ 50 | if(!isMuxStart){ 51 | if(mAudioTrack==-1&&mVideoTrack==-1){ 52 | try { 53 | mMuxer=new MediaMuxer(mPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); 54 | 55 | } catch (IOException e) { 56 | e.printStackTrace(); 57 | } 58 | } 59 | if(mMuxer!=null){ 60 | int ret=-1; 61 | String mime=mediaFormat.getString(MediaFormat.KEY_MIME); 62 | if(mime.startsWith("audio")){ 63 | ret = mMuxer.addTrack(mediaFormat); 64 | mAudioTrack=ret; 65 | }else if(mime.startsWith("video")){ 66 | ret = mMuxer.addTrack(mediaFormat); 67 | mVideoTrack=ret; 68 | if(mAudioTrack<0&&waiAudio){ 69 | try { 70 | LOCK.wait(2000); 71 | } catch (InterruptedException e) { 72 | e.printStackTrace(); 73 | } 74 | } 75 | mMuxer.start(); 76 | isMuxStart=true; 77 | Log.e("wuwang","add video track:"+ret); 78 | } 79 | return ret; 80 | } 81 | } 82 | } 83 | return -1; 84 | } 85 | 86 | @Override 87 | public int addData(int track, HardMediaData hardMediaData) { 88 | boolean canMux=isMuxStart&&(track==mAudioTrack||track==mVideoTrack); 89 | if(canMux){ 90 | mMuxer.writeSampleData(track,hardMediaData.data,hardMediaData.info); 91 | return 0; 92 | } 93 | return -1; 94 | } 95 | 96 | @Override 97 | public void setOutputPath(String path) { 98 | this.mPath=path; 99 | } 100 | 101 | @Override 102 | public void close() { 103 | synchronized (LOCK){ 104 | try { 105 | if(isMuxStart){ 106 | isMuxStart=false; 107 | mAudioTrack=-1; 108 | mVideoTrack=-1; 109 | mMuxer.stop(); 110 | mMuxer.release(); 111 | mMuxer=null; 112 | 113 | } 114 | }catch (IllegalStateException e){ 115 | e.printStackTrace(); 116 | } 117 | 118 | } 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/hard/Recycler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.media.hard; 15 | 16 | import android.util.SparseArray; 17 | 18 | import java.util.concurrent.LinkedBlockingQueue; 19 | 20 | /** 21 | * Recycler 22 | * 23 | * @author wuwang 24 | * @version v1.0 2017:11:08 16:16 25 | */ 26 | class Recycler { 27 | 28 | private SparseArray> datas=new SparseArray<>(); 29 | 30 | public void put(int index,T t){ 31 | if(datas.indexOfKey(index)<0){ 32 | datas.append(index,new LinkedBlockingQueue()); 33 | } 34 | datas.get(index).add(t); 35 | } 36 | 37 | public T poll(int index){ 38 | if(datas.indexOfKey(index)>=0){ 39 | return datas.get(index).poll(); 40 | } 41 | return null; 42 | } 43 | 44 | public void clear(){ 45 | datas.clear(); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/player/AudioDecoder.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.media.player; 2 | 3 | import android.annotation.TargetApi; 4 | import android.media.MediaCodec; 5 | import android.media.MediaExtractor; 6 | import android.media.MediaFormat; 7 | import android.os.Build; 8 | 9 | import java.nio.ByteBuffer; 10 | 11 | /** 12 | * @author wuwang 13 | * @version 1.00 , 2018/09/27 14 | */ 15 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 16 | class AudioDecoder implements Runnable { 17 | 18 | private MediaExtractor extractor; 19 | private MediaCodec codec; 20 | 21 | private boolean threadFlag = false; 22 | private Thread thread; 23 | private long seekTime; 24 | private final Object SEEK_LOCK = new Object(); 25 | private int timeout = 1000; 26 | private MediaCodec.BufferInfo info; 27 | private IAudioProcessor processor; 28 | 29 | AudioDecoder(MediaExtractor extractor, MediaCodec codec){ 30 | this.extractor = extractor; 31 | this.codec = codec; 32 | this.info = new MediaCodec.BufferInfo(); 33 | } 34 | 35 | public void setAudioFormatChanged(IAudioProcessor processor){ 36 | this.processor = processor; 37 | } 38 | 39 | public void init(){ 40 | threadFlag = true; 41 | thread = new Thread(this); 42 | thread.start(); 43 | } 44 | 45 | public void seekTo(long time){ 46 | synchronized (SEEK_LOCK){ 47 | this.seekTime = time; 48 | } 49 | } 50 | 51 | private void checkAndDoSeek(){ 52 | if(seekTime >= 0){ 53 | synchronized (SEEK_LOCK){ 54 | if(seekTime >=0 ){ 55 | extractor.seekTo(seekTime,MediaExtractor.SEEK_TO_PREVIOUS_SYNC); 56 | } 57 | } 58 | } 59 | } 60 | 61 | private ByteBuffer getInputBuffer(MediaCodec codec, int index){ 62 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 63 | return codec.getInputBuffer(index); 64 | }else{ 65 | return codec.getInputBuffers()[index]; 66 | } 67 | } 68 | 69 | private ByteBuffer getOutputBuffer(MediaCodec codec, int index){ 70 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 71 | return codec.getOutputBuffer(index); 72 | }else{ 73 | return codec.getOutputBuffers()[index]; 74 | } 75 | } 76 | 77 | public void release(){ 78 | threadFlag = false; 79 | } 80 | 81 | @Override 82 | public void run() { 83 | while (threadFlag){ 84 | checkAndDoSeek(); 85 | int inputIndex = codec.dequeueInputBuffer(timeout); 86 | if(inputIndex >= 0){ 87 | ByteBuffer inputBuffer = getInputBuffer(codec,inputIndex); 88 | inputBuffer.position(0); 89 | int size = extractor.readSampleData(inputBuffer,0); 90 | if(size == -1){ 91 | //todo 最后一帧处理 92 | codec.queueInputBuffer(inputIndex,0,0,extractor.getSampleTime(),MediaCodec.BUFFER_FLAG_END_OF_STREAM); 93 | }else{ 94 | codec.queueInputBuffer(inputIndex,0,size,extractor.getSampleTime(),extractor.getSampleFlags()); 95 | } 96 | } 97 | while(true){ 98 | int outputIndex = codec.dequeueOutputBuffer(info,timeout); 99 | if (outputIndex >= 0) { 100 | if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) { 101 | ByteBuffer outputBuffer = getOutputBuffer(codec,outputIndex); 102 | if(processor != null){ 103 | ByteBufferData data = new ByteBufferData(); 104 | data.data = outputBuffer; 105 | data.length = info.size; 106 | data.offset = info.offset; 107 | data.timeUs = info.presentationTimeUs; 108 | data.flag = info.flags; 109 | processor.processAudioData(data); 110 | } 111 | codec.releaseOutputBuffer(outputIndex, false); 112 | if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { 113 | //todo 最后一帧处理 114 | break; 115 | } 116 | } else { 117 | codec.releaseOutputBuffer(outputIndex, false); 118 | } 119 | } else if (outputIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { 120 | MediaFormat format = codec.getOutputFormat(); 121 | if(processor != null){ 122 | int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE); 123 | int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT); 124 | processor.onAudioFormatChanged(sampleRate,channelCount); 125 | } 126 | } else if(outputIndex == MediaCodec.INFO_TRY_AGAIN_LATER){ 127 | break; 128 | } 129 | } 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/player/BaseAudioDecoder.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.media.player; 2 | 3 | import android.media.MediaExtractor; 4 | import android.media.MediaFormat; 5 | 6 | /** 7 | * @author wuwang 8 | * @version 1.00 , 2018/09/28 9 | */ 10 | public abstract class BaseAudioDecoder implements IDecoder,ITimeObserver { 11 | 12 | protected IAudioProcessor processor; 13 | protected MediaExtractor extractor; 14 | protected MediaFormat format; 15 | protected long seekToTimeUs = -1; 16 | protected ITimeObserver observer; 17 | public boolean loop = false; 18 | 19 | public void setAudioProcessor(IAudioProcessor processor){ 20 | this.processor = processor; 21 | } 22 | 23 | public void setTimeObserver(ITimeObserver observer){ 24 | this.observer = observer; 25 | } 26 | 27 | public void init(MediaExtractor extractor, MediaFormat codec) { 28 | this.extractor = extractor; 29 | this.format = codec; 30 | } 31 | 32 | @Override 33 | public void seekTo(long timeUs) { 34 | this.seekToTimeUs = timeUs; 35 | } 36 | 37 | public void setLoop(boolean loop){ 38 | this.loop = loop; 39 | } 40 | 41 | @Override 42 | public boolean update(long time) { 43 | if(observer != null){ 44 | observer.update(time); 45 | } 46 | return true; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/player/BaseVideoDecoder.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.media.player; 2 | 3 | import android.graphics.SurfaceTexture; 4 | import android.media.MediaExtractor; 5 | import android.media.MediaFormat; 6 | import android.view.Surface; 7 | 8 | /** 9 | * @author wuwang 10 | * @version 1.00 , 2018/09/28 11 | */ 12 | public abstract class BaseVideoDecoder implements IDecoder,ITimeObserver { 13 | 14 | protected ITextureProcessor processor; 15 | protected MediaExtractor extractor; 16 | protected MediaFormat format; 17 | protected long seekToTimeUs = -1; 18 | protected Surface surface; 19 | 20 | public BaseVideoDecoder(){ 21 | 22 | } 23 | 24 | public void init(MediaExtractor extractor, MediaFormat codec, SurfaceTexture texture){ 25 | this.extractor = extractor; 26 | this.format = codec; 27 | this.surface = new Surface(texture); 28 | } 29 | 30 | public void setTextureProcessor(ITextureProcessor processor){ 31 | this.processor = processor; 32 | } 33 | 34 | @Override 35 | public void seekTo(long timeUs) { 36 | this.seekToTimeUs = timeUs; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/player/ByteBufferData.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.media.player; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | /** 6 | * @author wuwang 7 | * @version 1.00 , 2018/09/28 8 | */ 9 | public class ByteBufferData{ 10 | public ByteBuffer data; 11 | public int offset; 12 | public int length; 13 | public long timeUs; 14 | public int flag; 15 | } 16 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/player/EPlayerException.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.media.player; 2 | 3 | /** 4 | * @author wuwang 5 | * @version 1.00 , 2018/10/05 6 | */ 7 | public class EPlayerException extends RuntimeException { 8 | 9 | public EPlayerException(String message){ 10 | super(message); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/player/IAudioProcessor.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.media.player; 2 | 3 | /** 4 | * 处理音频数据接口 5 | * @author wuwang 6 | * @version 1.00 , 2018/09/28 7 | */ 8 | public interface IAudioProcessor { 9 | 10 | /** 11 | * 音频信息发生改变 12 | * @param sampleRate 音频采样率 13 | * @param channelCount 音频通道数 14 | */ 15 | void onAudioFormatChanged(int sampleRate, int channelCount); 16 | 17 | 18 | /** 19 | * 处理音频数据 20 | * @param data 输入的音频数据 21 | * @return 处理后的数据 22 | */ 23 | ByteBufferData processAudioData(ByteBufferData data); 24 | 25 | /** 26 | * 销毁音频处理相关资源 27 | */ 28 | void release(); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/player/IDecoder.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.media.player; 2 | 3 | /** 4 | * @author wuwang 5 | * @version 1.00 , 2018/09/28 6 | */ 7 | public interface IDecoder { 8 | 9 | /** 10 | * seek到指定位置再解码 11 | * @param timeUs 时间us 12 | */ 13 | void seekTo(long timeUs); 14 | 15 | /** 16 | * 开始解码 17 | */ 18 | void start(); 19 | 20 | /** 21 | * 暂停解码 22 | */ 23 | void pause(); 24 | 25 | /** 26 | * 停止解码 27 | */ 28 | void stop(); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/player/ITextureProcessor.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.media.player; 2 | 3 | /** 4 | * @author wuwang 5 | * @version 1.00 , 2018/10/05 6 | */ 7 | public interface ITextureProcessor { 8 | 9 | int process(int textureId); 10 | 11 | void release(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/player/ITimeObserver.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.media.player; 2 | 3 | /** 4 | * @author wuwang 5 | * @version 1.00 , 2018/10/10 6 | */ 7 | public interface ITimeObserver { 8 | 9 | /** 10 | * 通知观察者当前时间 11 | * @param time 时间戳 12 | * @return 观察者是否处理完成 13 | */ 14 | boolean update(long time); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/video/CameraProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.media.video; 15 | 16 | import android.graphics.Point; 17 | import android.graphics.SurfaceTexture; 18 | import android.hardware.Camera; 19 | 20 | import com.wuwang.aavt.log.AvLog; 21 | 22 | import java.io.IOException; 23 | import java.util.Collections; 24 | import java.util.Comparator; 25 | import java.util.List; 26 | import java.util.concurrent.Semaphore; 27 | 28 | /** 29 | * CameraProvider 相机数据 30 | * 31 | * @author wuwang 32 | * @version v1.0 2017:10:26 18:09 33 | */ 34 | public class CameraProvider implements ITextureProvider { 35 | 36 | private Camera mCamera; 37 | private int cameraId=0; 38 | private int minWidth = 720; 39 | private float rate = 1.67f; 40 | private Semaphore mFrameSem; 41 | private String tag=getClass().getSimpleName(); 42 | 43 | @Override 44 | public Point open(final SurfaceTexture surface) { 45 | final Point size=new Point(); 46 | try { 47 | mFrameSem=new Semaphore(0); 48 | mCamera=Camera.open(cameraId); 49 | onCameraOpened(mCamera); 50 | mCamera.setPreviewTexture(surface); 51 | surface.setOnFrameAvailableListener(frameListener); 52 | Camera.Size s=mCamera.getParameters().getPreviewSize(); 53 | mCamera.startPreview(); 54 | size.x=s.height; 55 | size.y=s.width; 56 | AvLog.i(tag,"Camera Opened"); 57 | } catch (IOException e) { 58 | e.printStackTrace(); 59 | } 60 | return size; 61 | } 62 | 63 | /** 64 | * Camera Open后,Preview前被调用的函数 65 | * @param camera 打开的Camera 66 | */ 67 | protected void onCameraOpened(Camera camera){ 68 | //小米5、5s这类奇葩手机不调用setParameters这句会导致图像预览方向错误 69 | Camera.Parameters param = camera.getParameters(); 70 | List sizes = param.getSupportedPreviewSizes(); 71 | Collections.sort(sizes, new Comparator() { 72 | @Override 73 | public int compare(android.hardware.Camera.Size o1, android.hardware.Camera.Size o2) { 74 | return o1.width - o2.width; 75 | } 76 | }); 77 | for (android.hardware.Camera.Size s : sizes) { 78 | if (s.width >= minWidth) { 79 | if (rate > 1.4) { 80 | if (s.width / (float) s.height > 1.4) { 81 | param.setPreviewSize(s.width, s.height); 82 | param.set("video-size", s.width + "x" + s.height); 83 | break; 84 | } 85 | } else { 86 | if (s.width / (float) s.height < 1.4) { 87 | param.setPreviewSize(s.width, s.height); 88 | param.set("video-size", s.width + "x" + s.height); 89 | break; 90 | } 91 | } 92 | } 93 | } 94 | List mode = param.getSupportedFocusModes(); 95 | if(mode.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)){ 96 | param.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); 97 | } 98 | mCamera.setParameters(param); 99 | } 100 | 101 | public void setCameraSize(int minWidth,float rate){ 102 | this.minWidth = minWidth; 103 | this.rate = rate; 104 | } 105 | 106 | public void switchCamera(){ 107 | cameraId^=1; 108 | } 109 | 110 | public void setDefaultCamera(int id){ 111 | cameraId = id; 112 | } 113 | 114 | @Override 115 | public void close() { 116 | mFrameSem.drainPermits(); 117 | mFrameSem.release(); 118 | 119 | mCamera.stopPreview(); 120 | mCamera.release(); 121 | mCamera=null; 122 | } 123 | 124 | @Override 125 | public boolean frame() { 126 | try { 127 | mFrameSem.acquire(); 128 | } catch (InterruptedException e) { 129 | e.printStackTrace(); 130 | } 131 | return false; 132 | } 133 | 134 | @Override 135 | public long getTimeStamp() { 136 | return -1; 137 | } 138 | 139 | @Override 140 | public boolean isLandscape() { 141 | return true; 142 | } 143 | 144 | private SurfaceTexture.OnFrameAvailableListener frameListener=new SurfaceTexture.OnFrameAvailableListener() { 145 | 146 | @Override 147 | public void onFrameAvailable(SurfaceTexture surfaceTexture) { 148 | AvLog.d(tag,"onFrameAvailable"); 149 | mFrameSem.drainPermits(); 150 | mFrameSem.release(); 151 | } 152 | 153 | }; 154 | 155 | } 156 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/media/video/ITextureProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.media.video; 15 | 16 | import android.graphics.Point; 17 | import android.graphics.SurfaceTexture; 18 | 19 | import com.wuwang.aavt.media.av.ICloseable; 20 | 21 | /** 22 | * ITextureProvider 23 | * 24 | * @author wuwang 25 | * @version v1.0 2017:10:26 18:18 26 | */ 27 | public interface ITextureProvider extends ICloseable { 28 | 29 | /** 30 | * 打开视频流数据源 31 | * @param surface 数据流输出到此 32 | * @return 视频流的宽高 33 | */ 34 | Point open(SurfaceTexture surface); 35 | 36 | /** 37 | * 获取一帧数据 38 | * @return 是否最后一帧 39 | */ 40 | boolean frame(); 41 | 42 | /** 43 | * 获取当前帧时间戳 44 | * @return 时间戳 45 | */ 46 | long getTimeStamp(); 47 | 48 | /** 49 | * 视频流是否是横向的 50 | * @return true or false 51 | */ 52 | boolean isLandscape(); 53 | 54 | } -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/utils/GpuUtils.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.utils; 2 | 3 | import android.content.res.Resources; 4 | import android.opengl.GLES11Ext; 5 | import android.opengl.GLES20; 6 | import com.wuwang.aavt.log.AvLog; 7 | 8 | import java.io.InputStream; 9 | 10 | import javax.microedition.khronos.opengles.GL10; 11 | 12 | public enum GpuUtils { 13 | ; 14 | /** 15 | * 读取Assets中的文本文件 16 | * @param mRes res 17 | * @param path 文件路径 18 | * @return 文本内容 19 | */ 20 | public static String readText(Resources mRes,String path){ 21 | StringBuilder result=new StringBuilder(); 22 | try{ 23 | InputStream is=mRes.getAssets().open(path); 24 | int ch; 25 | byte[] buffer=new byte[1024]; 26 | while (-1!=(ch=is.read(buffer))){ 27 | result.append(new String(buffer,0,ch)); 28 | } 29 | }catch (Exception e){ 30 | return null; 31 | } 32 | return result.toString().replaceAll("\\r\\n","\n"); 33 | } 34 | 35 | /** 36 | * 加载Shader 37 | * @param shaderType Shader类型 38 | * @param source Shader代码 39 | * @return shaderId 40 | */ 41 | public static int loadShader(int shaderType,String source){ 42 | if(source==null){ 43 | glError(1,"Shader source ==null : shaderType ="+shaderType); 44 | return 0; 45 | } 46 | int shader= GLES20.glCreateShader(shaderType); 47 | if(0!=shader){ 48 | GLES20.glShaderSource(shader,source); 49 | GLES20.glCompileShader(shader); 50 | int[] compiled=new int[1]; 51 | GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS,compiled,0); 52 | if(compiled[0]==0){ 53 | glError(1,"Could not compile shader:"+shaderType); 54 | glError(1,"GLES20 Error:"+ GLES20.glGetShaderInfoLog(shader)); 55 | GLES20.glDeleteShader(shader); 56 | shader=0; 57 | } 58 | } 59 | return shader; 60 | } 61 | 62 | /** 63 | * 通过字符串创建GL程序 64 | * @param vertexSource 顶点着色器 65 | * @param fragmentSource 片元着色器 66 | * @return programId 67 | */ 68 | public static int createGLProgram(String vertexSource, String fragmentSource){ 69 | int vertex=loadShader(GLES20.GL_VERTEX_SHADER,vertexSource); 70 | if(vertex==0){ 71 | return 0; 72 | } 73 | int fragment=loadShader(GLES20.GL_FRAGMENT_SHADER,fragmentSource); 74 | if(fragment==0){ 75 | return 0; 76 | } 77 | int program= GLES20.glCreateProgram(); 78 | if(program!=0){ 79 | GLES20.glAttachShader(program,vertex); 80 | GLES20.glAttachShader(program,fragment); 81 | GLES20.glLinkProgram(program); 82 | int[] linkStatus=new int[1]; 83 | GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS,linkStatus,0); 84 | if(linkStatus[0]!= GLES20.GL_TRUE){ 85 | glError(1,"Could not link program:"+ GLES20.glGetProgramInfoLog(program)); 86 | GLES20.glDeleteProgram(program); 87 | program=0; 88 | } 89 | } 90 | return program; 91 | } 92 | 93 | /** 94 | * 通过assets中的文件创建GL程序 95 | * @param res res 96 | * @param vertex 顶点作色器路径 97 | * @param fragment 片元着色器路径 98 | * @return programId 99 | */ 100 | public static int createGLProgramByAssetsFile(Resources res,String vertex,String fragment){ 101 | return createGLProgram(readText(res,vertex),readText(res,fragment)); 102 | } 103 | 104 | private static void glError(int code,Object index){ 105 | AvLog.e("glError:"+code+"---"+index); 106 | } 107 | 108 | public static int createTextureID(boolean isOes) { 109 | int target= GLES20.GL_TEXTURE_2D; 110 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) { 111 | target = isOes? GLES11Ext.GL_TEXTURE_EXTERNAL_OES: GLES20.GL_TEXTURE_2D; 112 | } 113 | int[] texture = new int[1]; 114 | GLES20.glGenTextures(1, texture, 0); 115 | GLES20.glBindTexture(target, texture[0]); 116 | GLES20.glTexParameterf(target, 117 | GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); 118 | GLES20.glTexParameterf(target, 119 | GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); 120 | GLES20.glTexParameteri(target, 121 | GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE); 122 | GLES20.glTexParameteri(target, 123 | GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE); 124 | return texture[0]; 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /aavt/src/main/java/com/wuwang/aavt/utils/MatrixUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.utils; 15 | 16 | import android.opengl.Matrix; 17 | import android.widget.ImageView; 18 | 19 | /** 20 | * MatrixUtils 21 | * 22 | * @author wuwang 23 | * @version v1.0 2017:11:01 10:41 24 | */ 25 | public enum MatrixUtils { 26 | ; 27 | public static final int TYPE_FITXY=0; 28 | public static final int TYPE_CENTERCROP=1; 29 | public static final int TYPE_CENTERINSIDE=2; 30 | public static final int TYPE_FITSTART=3; 31 | public static final int TYPE_FITEND=4; 32 | 33 | /** 34 | * 获取一个新的原始纹理坐标,每次调用,都会重新创建 35 | * @return 坐标数组 36 | */ 37 | public static float[] getOriginalTextureCo(){ 38 | return new float[]{ 39 | 0.0f,0.0f, 40 | 0.0f,1.0f, 41 | 1.0f,0.0f, 42 | 1.0f,1.0f 43 | }; 44 | } 45 | 46 | /** 47 | * 获取一个新的原始顶点坐标,每次调用,都会重新创建 48 | * @return 坐标数组 49 | */ 50 | public static float[] getOriginalVertexCo(){ 51 | return new float[]{ 52 | -1.0f,-1.0f, 53 | -1.0f,1.0f, 54 | 1.0f,-1.0f, 55 | 1.0f,1.0f 56 | }; 57 | } 58 | 59 | /** 60 | * 获取一个新的4*4单位矩阵 61 | * @return 矩阵数组 62 | */ 63 | public static float[] getOriginalMatrix(){ 64 | return new float[]{ 65 | 1,0,0,0, 66 | 0,1,0,0, 67 | 0,0,1,0, 68 | 0,0,0,1 69 | }; 70 | } 71 | 72 | /** 73 | * 根据预览的大小和图像的大小,计算合适的变换矩阵 74 | * @param matrix 接收变换矩阵的数组 75 | * @param type 变换的类型,参考{@link #TYPE_CENTERCROP}、{@link #TYPE_FITEND}、{@link #TYPE_CENTERINSIDE}、{@link #TYPE_FITSTART}、{@link #TYPE_FITXY},对应{@link android.widget.ImageView}的{@link android.widget.ImageView#setScaleType(ImageView.ScaleType)} 76 | * @param imgWidth 图像的宽度 77 | * @param imgHeight 图像的高度 78 | * @param viewWidth 视图的宽度 79 | * @param viewHeight 视图的高度 80 | */ 81 | public static void getMatrix(float[] matrix,int type,int imgWidth,int imgHeight,int viewWidth, 82 | int viewHeight){ 83 | if(imgHeight>0&&imgWidth>0&&viewWidth>0&&viewHeight>0){ 84 | float[] projection=new float[16]; 85 | float[] camera=new float[16]; 86 | if(type==TYPE_FITXY){ 87 | Matrix.orthoM(projection,0,-1,1,-1,1,1,3); 88 | Matrix.setLookAtM(camera,0,0,0,1,0,0,0,0,1,0); 89 | Matrix.multiplyMM(matrix,0,projection,0,camera,0); 90 | return; 91 | } 92 | float sWhView=(float)viewWidth/viewHeight; 93 | float sWhImg=(float)imgWidth/imgHeight; 94 | if(sWhImg>sWhView){ 95 | switch (type){ 96 | case TYPE_CENTERCROP: 97 | Matrix.orthoM(projection,0,-sWhView/sWhImg,sWhView/sWhImg,-1,1,1,3); 98 | break; 99 | case TYPE_CENTERINSIDE: 100 | Matrix.orthoM(projection,0,-1,1,-sWhImg/sWhView,sWhImg/sWhView,1,3); 101 | break; 102 | case TYPE_FITSTART: 103 | Matrix.orthoM(projection,0,-1,1,1-2*sWhImg/sWhView,1,1,3); 104 | break; 105 | case TYPE_FITEND: 106 | Matrix.orthoM(projection,0,-1,1,-1,2*sWhImg/sWhView-1,1,3); 107 | break; 108 | default: 109 | break; 110 | } 111 | }else{ 112 | switch (type){ 113 | case TYPE_CENTERCROP: 114 | Matrix.orthoM(projection,0,-1,1,-sWhImg/sWhView,sWhImg/sWhView,1,3); 115 | break; 116 | case TYPE_CENTERINSIDE: 117 | Matrix.orthoM(projection,0,-sWhView/sWhImg,sWhView/sWhImg,-1,1,1,3); 118 | break; 119 | case TYPE_FITSTART: 120 | Matrix.orthoM(projection,0,-1,2*sWhView/sWhImg-1,-1,1,1,3); 121 | break; 122 | case TYPE_FITEND: 123 | Matrix.orthoM(projection,0,1-2*sWhView/sWhImg,1,-1,1,1,3); 124 | break; 125 | default: 126 | break; 127 | } 128 | } 129 | Matrix.setLookAtM(camera,0,0,0,1,0,0,0,0,1,0); 130 | Matrix.multiplyMM(matrix,0,projection,0,camera,0); 131 | } 132 | } 133 | 134 | /** 135 | * 翻转矩阵 136 | * @param m 需要被翻转的矩阵 137 | * @param x 是否x轴左右翻转 138 | * @param y 是否y轴左右翻转 139 | * @return 传入的矩阵 140 | */ 141 | public static float[] flip(float[] m,boolean x,boolean y){ 142 | if(x||y){ 143 | Matrix.scaleM(m,0,x?-1:1,y?-1:1,1); 144 | } 145 | return m; 146 | } 147 | 148 | } 149 | 150 | -------------------------------------------------------------------------------- /aavt/src/main/res/values/attr.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /aavt/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | AAVT 3 | 4 | -------------------------------------------------------------------------------- /aavt/src/test/java/com/wuwang/aavt/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | google() 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.5.2' 10 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1' 11 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3' 12 | 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | jcenter() 21 | google() 22 | } 23 | } 24 | 25 | 26 | ext{ 27 | vCode=25 28 | vName="a0.2.5" 29 | } 30 | 31 | task clean(type: Delete) { 32 | delete rootProject.buildDir 33 | } 34 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /examples/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.3" 6 | defaultConfig { 7 | applicationId "com.wuwang.aavt.examples" 8 | minSdkVersion 14 9 | targetSdkVersion 25 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 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:25.3.1' 28 | compile 'com.android.support.constraint:constraint-layout:1.0.2' 29 | testCompile 'junit:junit:4.12' 30 | compile project(':aavt') 31 | } 32 | -------------------------------------------------------------------------------- /examples/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:\Android\android-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 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /examples/src/androidTest/java/com/wuwang/aavt/examples/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.examples; 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.wuwang.aavt", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 28 | 29 | 31 | 32 | 34 | 35 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /examples/src/main/java/com/wuwang/aavt/examples/CameraRecorderActivity.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.examples; 2 | 3 | import android.content.Intent; 4 | import android.net.Uri; 5 | import android.os.Bundle; 6 | import android.os.Environment; 7 | import android.os.Handler; 8 | import android.os.Looper; 9 | import android.support.annotation.Nullable; 10 | import android.support.v7.app.AppCompatActivity; 11 | import android.view.SurfaceHolder; 12 | import android.view.SurfaceView; 13 | import android.view.View; 14 | import android.widget.TextView; 15 | import android.widget.Toast; 16 | 17 | import com.wuwang.aavt.av.VideoCapture; 18 | 19 | public class CameraRecorderActivity extends AppCompatActivity{ 20 | 21 | private SurfaceView mSurfaceView; 22 | private TextView mTvPreview,mTvRecord; 23 | private boolean isPreviewOpen=false; 24 | private boolean isRecordOpen=false; 25 | private int mCameraWidth,mCameraHeight; 26 | 27 | private VideoCapture mCamera; 28 | 29 | private String tempPath= Environment.getExternalStorageDirectory().getAbsolutePath()+"/test.mp4"; 30 | 31 | @Override 32 | protected void onCreate(@Nullable Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | setContentView(R.layout.activity_camera_record); 35 | mSurfaceView= (SurfaceView) findViewById(R.id.mSurfaceView); 36 | mTvRecord= (TextView) findViewById(R.id.mTvRec); 37 | mTvPreview= (TextView) findViewById(R.id.mTvShow); 38 | 39 | mCamera =new VideoCapture(getApplicationContext()); 40 | mCamera.setProperty(VideoCapture.KEY_OUTPUT_WIDTH, 368); 41 | mCamera.setProperty(VideoCapture.KEY_OUTPUT_HEIGHT,640); 42 | mCamera.setProperty(VideoCapture.KEY_OUTPUT_PATH,tempPath); 43 | 44 | mSurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() { 45 | @Override 46 | public void surfaceCreated(SurfaceHolder holder) { 47 | // GroupFilter filter=new GroupFilter(getResources()); 48 | // mCamera.setRenderer(filter); 49 | // filter.addFilter(new StickFigureFilter(getResources())); 50 | // filter.addFilter(new BeautyFilter(getResources()).setBeautyLevel(4)); 51 | // filter.addFilter(new WaterMarkFilter().setMarkPosition(30,10,100,76).setMark(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))); 52 | } 53 | 54 | @Override 55 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 56 | mCamera.setProperty(VideoCapture.KEY_PREVIEW_WIDTH,width); 57 | mCamera.setProperty(VideoCapture.KEY_PREVIEW_HEIGHT,height); 58 | mCamera.open(0); 59 | mCamera.setPreviewSurface(holder.getSurface()); 60 | mCamera.startPreview(); 61 | isPreviewOpen=true; 62 | } 63 | 64 | @Override 65 | public void surfaceDestroyed(SurfaceHolder holder) { 66 | mCamera.stopPreview(); 67 | mCamera.close(); 68 | } 69 | }); 70 | } 71 | 72 | public void onClick(View view){ 73 | switch (view.getId()){ 74 | case R.id.mTvShow: 75 | isPreviewOpen=!isPreviewOpen; 76 | mTvPreview.setText(isPreviewOpen?"关预览":"开预览"); 77 | if(isPreviewOpen){ 78 | mCamera.startPreview(); 79 | }else{ 80 | mCamera.stopPreview(); 81 | } 82 | break; 83 | case R.id.mTvRec: 84 | isRecordOpen=!isRecordOpen; 85 | mTvRecord.setText(isRecordOpen?"关录制":"开录制"); 86 | if(isRecordOpen){ 87 | mCamera.startRecord(); 88 | }else{ 89 | mCamera.stopRecord(); 90 | new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { 91 | @Override 92 | public void run() { 93 | Intent v=new Intent(Intent.ACTION_VIEW); 94 | v.setDataAndType(Uri.parse(tempPath),"video/mp4"); 95 | if(v.resolveActivity(getPackageManager()) != null){ 96 | //startActivity(v); 97 | }else{ 98 | Toast.makeText(CameraRecorderActivity.this, 99 | "无法找到默认媒体软件打开:"+tempPath, Toast.LENGTH_SHORT).show(); 100 | } 101 | } 102 | },1000); 103 | } 104 | break; 105 | default: 106 | break; 107 | } 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /examples/src/main/java/com/wuwang/aavt/examples/ExampleMp4ProcessActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Wuwang on 2017/9/11 3 | * Copyright © 2017年 深圳哎吖科技. All rights reserved. 4 | */ 5 | package com.wuwang.aavt.examples; 6 | 7 | import android.content.ContentResolver; 8 | import android.content.Intent; 9 | import android.net.Uri; 10 | import android.os.Bundle; 11 | import android.os.Environment; 12 | import android.support.annotation.Nullable; 13 | import android.support.v7.app.AppCompatActivity; 14 | import android.util.Log; 15 | import android.view.SurfaceHolder; 16 | import android.view.SurfaceView; 17 | import android.view.View; 18 | 19 | import com.wuwang.aavt.av.Mp4Processor2; 20 | 21 | public class ExampleMp4ProcessActivity extends AppCompatActivity { 22 | 23 | private SurfaceView mSurfaceView; 24 | private Mp4Processor2 mMp4Processor; 25 | private String tempPath= Environment.getExternalStorageDirectory().getAbsolutePath()+"/test.mp4"; 26 | 27 | @Override 28 | protected void onCreate(@Nullable Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_mp4); 31 | mMp4Processor=new Mp4Processor2(); 32 | mMp4Processor.setInputPath(Environment.getExternalStorageDirectory().getAbsolutePath()+"/a.mp4"); 33 | mMp4Processor.setOutputPath(tempPath); 34 | mSurfaceView= (SurfaceView) findViewById(R.id.mSurfaceView); 35 | mSurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() { 36 | @Override 37 | public void surfaceCreated(SurfaceHolder holder) { 38 | 39 | } 40 | 41 | @Override 42 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 43 | mMp4Processor.setSurface(holder); 44 | mMp4Processor.setPreviewSize(width, height); 45 | mMp4Processor.startPreview(); 46 | } 47 | 48 | @Override 49 | public void surfaceDestroyed(SurfaceHolder holder) { 50 | mMp4Processor.stopPreview(); 51 | } 52 | }); 53 | } 54 | 55 | public void onClick(View view){ 56 | switch (view.getId()){ 57 | case R.id.mOpen: 58 | Intent intent = new Intent(Intent.ACTION_GET_CONTENT); 59 | //intent.setType(“image/*”);//选择图片 60 | //intent.setType(“audio/*”); //选择音频 61 | intent.setType("video/mp4"); //选择视频 (mp4 3gp 是android支持的视频格式) 62 | //intent.setType(“video/*;image/*”);//同时选择视频和图片 63 | //intent.setType("*/*");//无类型限制 64 | intent.addCategory(Intent.CATEGORY_OPENABLE); 65 | startActivityForResult(intent, 1); 66 | break; 67 | case R.id.mProcess: 68 | mMp4Processor.startRecord(); 69 | mMp4Processor.open(); 70 | break; 71 | case R.id.mStop: 72 | mMp4Processor.stopRecord(); 73 | mMp4Processor.close(); 74 | break; 75 | case R.id.mPlay: 76 | Intent v=new Intent(Intent.ACTION_VIEW); 77 | v.setDataAndType(Uri.parse(tempPath),"video/mp4"); 78 | startActivity(v); 79 | break; 80 | default: 81 | break; 82 | } 83 | } 84 | @Override 85 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 86 | super.onActivityResult(requestCode, resultCode, data); 87 | if (resultCode == RESULT_OK) { 88 | String path = getRealFilePath(data.getData()); 89 | if (path != null) { 90 | mMp4Processor.setInputPath(path); 91 | } 92 | } 93 | } 94 | 95 | public String getRealFilePath(final Uri uri) { 96 | if (null == uri) return null; 97 | final String scheme = uri.getScheme(); 98 | String data = null; 99 | if (scheme == null) { 100 | Log.e("wuwang", "scheme is null"); 101 | data = uri.getPath(); 102 | } else if (ContentResolver.SCHEME_FILE.equals(scheme)) { 103 | data = uri.getPath(); 104 | Log.e("wuwang", "SCHEME_FILE"); 105 | } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) { 106 | data = GetPathFromUri4kitkat.getPath(getApplicationContext(), uri); 107 | } 108 | return data; 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /examples/src/main/java/com/wuwang/aavt/examples/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.examples; 2 | 3 | import android.Manifest; 4 | import android.content.Intent; 5 | import android.support.annotation.NonNull; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.os.Bundle; 8 | import android.view.View; 9 | import android.widget.Toast; 10 | 11 | public class MainActivity extends AppCompatActivity { 12 | 13 | private PermissionAsker mAsker; 14 | private final int REQUEST_CODE_VIDEO_PLAY = 1; 15 | 16 | @Override 17 | protected void onCreate(Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | mAsker=new PermissionAsker(10,new Runnable() { 20 | @Override 21 | public void run() { 22 | setContentView(R.layout.activity_main); 23 | } 24 | }, new Runnable() { 25 | @Override 26 | public void run() { 27 | Toast.makeText(MainActivity.this, "必要权限被拒绝,应用退出", 28 | Toast.LENGTH_SHORT).show(); 29 | finish(); 30 | } 31 | }).askPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE, 32 | Manifest.permission.CAMERA,Manifest.permission.RECORD_AUDIO); 33 | } 34 | 35 | @Override 36 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 37 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 38 | mAsker.onRequestPermissionsResult(grantResults); 39 | } 40 | 41 | @Override 42 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 43 | super.onActivityResult(requestCode, resultCode, data); 44 | if(data != null && data.getData() != null){ 45 | if(REQUEST_CODE_VIDEO_PLAY == requestCode){ 46 | String path = GetPathFromUri4kitkat.getPath(this,data.getData()); 47 | Intent intent = new Intent(this,VideoPlayerActivity.class); 48 | intent.putExtra("videoPath",path); 49 | startActivity(intent); 50 | } 51 | } 52 | } 53 | 54 | public void onClick(View view){ 55 | switch (view.getId()){ 56 | case R.id.mMp4Process: 57 | startActivity(new Intent(this,ExampleMp4ProcessActivity.class)); 58 | break; 59 | case R.id.mCameraRecord: 60 | startActivity(new Intent(this,CameraRecorderActivity.class)); 61 | break; 62 | case R.id.mYuvExport: 63 | startActivity(new Intent(this,YuvExportActivity.class)); 64 | break; 65 | case R.id.mPlayVideo: 66 | Intent intent = new Intent(Intent.ACTION_GET_CONTENT); 67 | intent.setType("video/*"); 68 | startActivityForResult(intent,REQUEST_CODE_VIDEO_PLAY); 69 | break; 70 | default:break; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /examples/src/main/java/com/wuwang/aavt/examples/PermissionAsker.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.wuwang.aavt.examples; 15 | 16 | import android.app.Activity; 17 | import android.content.pm.PackageManager; 18 | import android.support.v4.app.ActivityCompat; 19 | 20 | /** 21 | * PermissionUtils 22 | * 23 | * @author wuwang 24 | * @version v1.0 2017:11:16 16:47 25 | */ 26 | public class PermissionAsker { 27 | 28 | private Runnable mOkRun=RUN; 29 | private Runnable mDeniRun=RUN; 30 | private int mReqCode=1; 31 | 32 | public PermissionAsker(){} 33 | 34 | public PermissionAsker(int code,Runnable ok,Runnable deni){ 35 | this.mReqCode=code; 36 | this.mOkRun=ok; 37 | this.mDeniRun=deni; 38 | } 39 | 40 | public void setReqCode(int code){ 41 | this.mReqCode=code; 42 | } 43 | 44 | public void setSuccedCallback(Runnable run){ 45 | this.mOkRun=run; 46 | } 47 | 48 | public void setFailedCallback(Runnable run){ 49 | this.mDeniRun=run; 50 | } 51 | 52 | public PermissionAsker askPermission(Activity context,String ... permission){ 53 | int result=0; 54 | for (String p:permission){ 55 | result+=ActivityCompat.checkSelfPermission(context,p); 56 | } 57 | if(result==0){ 58 | mOkRun.run(); 59 | }else{ 60 | ActivityCompat.requestPermissions(context,permission,mReqCode); 61 | } 62 | return this; 63 | } 64 | 65 | public void onRequestPermissionsResult(int[] grantResults){ 66 | boolean b=true; 67 | for (int a:grantResults){ 68 | b&=(a== PackageManager.PERMISSION_GRANTED); 69 | } 70 | if (grantResults.length > 0&&b) { 71 | mOkRun.run(); 72 | } else { 73 | mDeniRun.run(); 74 | } 75 | } 76 | 77 | 78 | private static final Runnable RUN=new Runnable() { 79 | @Override 80 | public void run() { 81 | 82 | } 83 | }; 84 | 85 | 86 | } 87 | -------------------------------------------------------------------------------- /examples/src/main/java/com/wuwang/aavt/examples/VideoPlayerActivity.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.aavt.examples; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.view.View; 7 | 8 | import com.wuwang.aavt.gl.CandyFilter; 9 | import com.wuwang.aavt.gl.GrayFilter; 10 | import com.wuwang.aavt.media.player.EffectMediaView; 11 | 12 | /** 13 | * @author wuwang 14 | * @version 1.00 , 2019/03/13 15 | */ 16 | public class VideoPlayerActivity extends AppCompatActivity { 17 | 18 | private EffectMediaView playerView; 19 | private String videoPath; 20 | 21 | @Override 22 | protected void onCreate(@Nullable Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | setContentView(R.layout.activity_player); 25 | playerView = (EffectMediaView) findViewById(R.id.playerView); 26 | videoPath = getIntent().getStringExtra("videoPath"); 27 | playerView.setRenderer(new CandyFilter(getResources())); 28 | playerView.setDataSource(videoPath); 29 | playerView.start(); 30 | } 31 | 32 | @Override 33 | protected void onResume() { 34 | super.onResume(); 35 | playerView.onResume(); 36 | } 37 | 38 | @Override 39 | protected void onPause() { 40 | super.onPause(); 41 | playerView.onPause(); 42 | } 43 | 44 | @Override 45 | protected void onDestroy() { 46 | super.onDestroy(); 47 | playerView.onDestroy(); 48 | } 49 | 50 | public void onPlay(View view){ 51 | playerView.start(); 52 | } 53 | 54 | public void onStop(View view){ 55 | playerView.stop(); 56 | } 57 | 58 | public void onPause(View view){ 59 | playerView.pause(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /examples/src/main/java/com/wuwang/aavt/examples/VideoUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Created by Wuwang on 2017/10/11 3 | * Copyright © 2017年 深圳哎吖科技. All rights reserved. 4 | */ 5 | package com.wuwang.aavt.examples; 6 | 7 | import android.util.Log; 8 | 9 | import com.wuwang.aavt.av.Mp4Processor; 10 | import com.wuwang.aavt.core.Renderer; 11 | import com.wuwang.aavt.gl.BaseFilter; 12 | import com.wuwang.aavt.gl.LazyFilter; 13 | 14 | import java.io.IOException; 15 | 16 | 17 | public class VideoUtils { 18 | 19 | public static void transcodeVideoFile(String srcVideoFile, String dstVideoFile, int dstWidth, int dstHeight, int durationUS, OnProgress onProgress) throws IOException { 20 | final Mp4Processor processor=new Mp4Processor(); 21 | processor.setOutputPath(dstVideoFile); 22 | processor.setInputPath(srcVideoFile); 23 | processor.setOutputSize(dstWidth,dstHeight); 24 | processor.setOnCompleteListener(new Mp4Processor.OnProgressListener() { 25 | @Override 26 | public void onProgress(long max, long current) { 27 | 28 | } 29 | 30 | @Override 31 | public void onComplete(String path) { 32 | Log.e("wuwang","end:::::"+path); 33 | } 34 | }); 35 | processor.setRenderer(new Renderer() { 36 | 37 | BaseFilter mFilter; 38 | 39 | @Override 40 | public void create() { 41 | mFilter=new LazyFilter(); 42 | mFilter.create(); 43 | } 44 | 45 | @Override 46 | public void sizeChanged(int width, int height) { 47 | mFilter.sizeChanged(width, height); 48 | } 49 | 50 | @Override 51 | public void draw(int texture) { 52 | mFilter.draw(texture); 53 | Log.e("wuwang","getPresentationTime:"+processor.getPresentationTime()); 54 | } 55 | 56 | @Override 57 | public void destroy() { 58 | mFilter.destroy(); 59 | } 60 | }); 61 | processor.start(); 62 | } 63 | 64 | interface OnProgress{ 65 | void process(long time); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /examples/src/main/res/drawable/tv_start_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/src/main/res/layout/activity__export_yuv.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 21 | 35 | 36 | -------------------------------------------------------------------------------- /examples/src/main/res/layout/activity_camera_record.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | 9 | 23 | 24 | 40 | -------------------------------------------------------------------------------- /examples/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 |