├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── libs │ ├── gson-2.2.2.jar │ └── jna-min.jar ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── tiktokdemo │ │ └── lky │ │ └── tiktokdemo │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ ├── RBB.mp4 │ │ └── RISE.mp3 │ ├── java │ │ └── com │ │ │ ├── heyhou │ │ │ └── social │ │ │ │ └── video │ │ │ │ ├── AudioListener.java │ │ │ │ ├── FilterInfo.java │ │ │ │ ├── HeyhouAudio.java │ │ │ │ ├── HeyhouPlayer.java │ │ │ │ ├── HeyhouPlayerRender.java │ │ │ │ ├── HeyhouPlayerService.java │ │ │ │ ├── HeyhouRecorder.java │ │ │ │ ├── HeyhouVideo.java │ │ │ │ ├── OpenGlUtils.java │ │ │ │ ├── Rotation.java │ │ │ │ ├── TestRender.java │ │ │ │ ├── TextureRotationUtil.java │ │ │ │ ├── VideoEncoder.java │ │ │ │ ├── VideoInfo.java │ │ │ │ ├── VideoListener.java │ │ │ │ ├── VideoMetaInfo.java │ │ │ │ ├── VideoPlayListener.java │ │ │ │ ├── VideoTimeType.java │ │ │ │ ├── WaveInfo.java │ │ │ │ └── WavePlayListener.java │ │ │ └── tiktokdemo │ │ │ └── lky │ │ │ └── tiktokdemo │ │ │ ├── BaseApplication.java │ │ │ ├── Constant.java │ │ │ ├── HomeCallBack.java │ │ │ ├── MainActivity.java │ │ │ ├── record │ │ │ ├── RecordVideoActivity.java │ │ │ ├── VideoCropActivity.java │ │ │ ├── VideoPlayActivity.java │ │ │ ├── adapter │ │ │ │ ├── TidalPatRecordFilterAdapter.java │ │ │ │ └── TidalPatRecordPropAdapter.java │ │ │ ├── bean │ │ │ │ ├── LyricSignRangeInfo.java │ │ │ │ ├── MusicBean.java │ │ │ │ ├── RecordStudioUploadEvent.java │ │ │ │ ├── RecordingDemoBean.java │ │ │ │ ├── RecordingStudioInformationBean.java │ │ │ │ ├── SpecialEffectsParentType.java │ │ │ │ ├── SpecialEffectsProgressBean.java │ │ │ │ ├── SpecialEffectsType.java │ │ │ │ ├── TidalPatRecordDraftBean.java │ │ │ │ ├── TidalPatRecordFilterInfo.java │ │ │ │ ├── TidalPatUploadEvent.java │ │ │ │ ├── TidalPatUploadFinishEvent.java │ │ │ │ ├── VideoFrameBean.java │ │ │ │ └── VoiceFrequencyInfo.java │ │ │ ├── camera │ │ │ │ ├── MagicEngine.java │ │ │ │ ├── beautify │ │ │ │ │ └── MagicJni.java │ │ │ │ ├── camera │ │ │ │ │ ├── CameraEngine.java │ │ │ │ │ └── utils │ │ │ │ │ │ ├── CameraInfo.java │ │ │ │ │ │ └── CameraUtils.java │ │ │ │ ├── encoder │ │ │ │ │ ├── gles │ │ │ │ │ │ ├── EglCore.java │ │ │ │ │ │ └── EglSurfaceBase.java │ │ │ │ │ └── video │ │ │ │ │ │ ├── ImageEncoderCore.java │ │ │ │ │ │ ├── TextureMovieEncoder.java │ │ │ │ │ │ ├── VideoEncoderCore.java │ │ │ │ │ │ └── WindowSurface.java │ │ │ │ ├── filter │ │ │ │ │ ├── base │ │ │ │ │ │ ├── MagicBaseGroupFilter.java │ │ │ │ │ │ ├── MagicCameraInputFilter.java │ │ │ │ │ │ ├── MagicLookupFilter.java │ │ │ │ │ │ ├── MyBeautyFilter.java │ │ │ │ │ │ └── gpuimage │ │ │ │ │ │ │ ├── GPUImageAddBlendFilter.java │ │ │ │ │ │ │ ├── GPUImageBrightnessFilter.java │ │ │ │ │ │ │ ├── GPUImageContrastFilter.java │ │ │ │ │ │ │ ├── GPUImageExposureFilter.java │ │ │ │ │ │ │ ├── GPUImageFilter.java │ │ │ │ │ │ │ ├── GPUImageFilterGroup.java │ │ │ │ │ │ │ ├── GPUImageHueFilter.java │ │ │ │ │ │ │ ├── GPUImageLookupFilter.java │ │ │ │ │ │ │ ├── GPUImageMiniLookupFilter.java │ │ │ │ │ │ │ ├── GPUImageNormalBlendFilter.java │ │ │ │ │ │ │ ├── GPUImageOverlayBlendFilter.java │ │ │ │ │ │ │ ├── GPUImageSaturationFilter.java │ │ │ │ │ │ │ ├── GPUImageSharpenFilter.java │ │ │ │ │ │ │ ├── GPUImageTwoInputFilter.java │ │ │ │ │ │ │ ├── GPUImageVignetteFilter.java │ │ │ │ │ │ │ └── MagicBeautyFilter.java │ │ │ │ │ ├── helper │ │ │ │ │ │ ├── FilterInfo.java │ │ │ │ │ │ ├── MagicFilterType.java │ │ │ │ │ │ └── MagicPropFactory.java │ │ │ │ │ └── prop │ │ │ │ │ │ ├── PropDynamicFilter.java │ │ │ │ │ │ └── PropStaticGroupFilter.java │ │ │ │ ├── helper │ │ │ │ │ └── SavePictureTask.java │ │ │ │ ├── stmobileapi │ │ │ │ │ ├── STImageFormat.java │ │ │ │ │ ├── STMobile106.java │ │ │ │ │ ├── STMobileApiBridge.java │ │ │ │ │ ├── STMobileFaceAction.java │ │ │ │ │ ├── STMobileFaceDetection.java │ │ │ │ │ ├── STMobileMultiTrack106.java │ │ │ │ │ └── STUtils.java │ │ │ │ ├── test │ │ │ │ │ ├── GLBitmap.java │ │ │ │ │ └── MyGLRenderer.java │ │ │ │ ├── utils │ │ │ │ │ ├── MagicParams.java │ │ │ │ │ ├── OpenGlUtils.java │ │ │ │ │ ├── PointParseUtil.java │ │ │ │ │ ├── Rotation.java │ │ │ │ │ └── TextureRotationUtil.java │ │ │ │ └── widget │ │ │ │ │ ├── CameraFocusHintView.java │ │ │ │ │ ├── CommRecyclerViewHolder.java │ │ │ │ │ ├── MagicCameraLayout.java │ │ │ │ │ ├── MagicCameraView.java │ │ │ │ │ ├── MagicImageView.java │ │ │ │ │ ├── MaxLengthEditText.java │ │ │ │ │ ├── MentionEditText.java │ │ │ │ │ └── base │ │ │ │ │ └── MagicBaseView.java │ │ │ ├── effects │ │ │ │ ├── TidalPatSpecoalEffectsManager.java │ │ │ │ └── adapter │ │ │ │ │ ├── TidalPatSpecialEffectsFilterAdapter.java │ │ │ │ │ ├── TidalPatSpecialEffectsFilterClickListener.java │ │ │ │ │ └── TidalPatSpecialEffectsTimeAdapter.java │ │ │ ├── helper │ │ │ │ ├── MagicFilterFactory.java │ │ │ │ ├── RecordTimeType.java │ │ │ │ ├── TidalPatFilterType.java │ │ │ │ ├── TidalPatPropFactory.java │ │ │ │ ├── TidalPatPropInfo.java │ │ │ │ └── TidalPatPropType.java │ │ │ ├── manager │ │ │ │ ├── AudioTrackManager.java │ │ │ │ └── SpecialEffectsPlayManager.java │ │ │ ├── presenter │ │ │ │ ├── RecordVideoContract.java │ │ │ │ ├── RecordVideoPresenter.java │ │ │ │ ├── VideoPlayContract.java │ │ │ │ └── VideoPlayPresenter.java │ │ │ ├── thread │ │ │ │ └── AudioRecorder.java │ │ │ └── weight │ │ │ │ ├── BreakProgressView.java │ │ │ │ ├── CircleProgressView.java │ │ │ │ ├── CircleRecordView.java │ │ │ │ ├── CountDownTextView.java │ │ │ │ ├── NewSpeedLevelControllerView.java │ │ │ │ ├── ProgressAnimationListener.java │ │ │ │ ├── RecordStudioAdjustSeekBar.java │ │ │ │ ├── RecordStudioAdjustSeekBarLayout.java │ │ │ │ ├── ScaleRoundRectView.java │ │ │ │ ├── SpecialEffectsPlayView.java │ │ │ │ ├── SpecialEffectsSeekBar.java │ │ │ │ ├── SpecialEffectsSelectorButton.java │ │ │ │ ├── TidalPatAdjustSeekBar.java │ │ │ │ └── VideoCropViewBar.java │ │ │ └── utils │ │ │ ├── AnimatorUtils.java │ │ │ ├── AppUtil.java │ │ │ ├── BitmapUtil.java │ │ │ ├── CacheUtil.java │ │ │ ├── CheckPermissionUtil.java │ │ │ ├── CommonSelectDialog.java │ │ │ ├── DensityUtils.java │ │ │ ├── FileUtils.java │ │ │ ├── HomeCacheUtil.java │ │ │ ├── StringUtil.java │ │ │ └── ToastTool.java │ ├── jniLibs │ │ └── armeabi │ │ │ ├── libffmpeg.so │ │ │ ├── libheyhou_video.so │ │ │ ├── libhyphenate.so │ │ │ ├── libopenh264.so │ │ │ ├── libpldroidplayer.so │ │ │ ├── libspeex.so │ │ │ └── libyuv.so │ └── res │ │ ├── anim │ │ ├── anim_center_rotate.xml │ │ ├── dialog_enter.xml │ │ ├── dialog_exit.xml │ │ └── rotate_anim.xml │ │ ├── drawable-nodpi │ │ ├── bw03_lut.jpg │ │ ├── cf17_lut.jpg │ │ ├── cf19_lut.jpg │ │ ├── filter_original.png │ │ ├── fm05_lut.jpg │ │ ├── fm10_lut.jpg │ │ ├── fs10_lut.jpg │ │ ├── ins02_lut.jpg │ │ ├── mod09_lut.jpg │ │ ├── re03_lut.jpg │ │ ├── sf03_lut.jpg │ │ └── shuiying.png │ │ ├── drawable-v24 │ │ ├── bg_big_rect_white.xml │ │ ├── bg_common_pink_submit.xml │ │ ├── bg_round_half_transparency.xml │ │ ├── bg_tidal_pat_record_time_red_cricle.xml │ │ ├── ic_launcher_foreground.xml │ │ ├── pop_dialog_style.xml │ │ ├── shape_common_rec_checked.xml │ │ └── shape_round_theme.xml │ │ ├── drawable │ │ ├── bg_few_transparency_round.xml │ │ ├── bg_gradual_black_bottom.xml │ │ ├── bg_personal_show_video_speed_level.xml │ │ ├── bg_personal_show_video_speed_level_left.xml │ │ ├── bg_personal_show_video_speed_level_right.xml │ │ ├── bg_round_white.xml │ │ ├── bg_tidal_pat_filter_selected.xml │ │ ├── bg_tidal_pat_prop_selected.xml │ │ ├── bg_tidal_pat_record_gray.xml │ │ ├── bg_tidal_pat_record_time_count.xml │ │ ├── bg_tidal_pat_upload_save_btn.xml │ │ ├── bg_tidal_pat_upload_send_btn.xml │ │ ├── bg_white_stroke.xml │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_tidal_pat_record_upload.xml │ │ ├── activity_tidal_pat_record_video.xml │ │ ├── activity_tidal_pat_video_crop.xml │ │ ├── dialog_common_select.xml │ │ ├── dialog_post_pic.xml │ │ ├── item_common_select.xml │ │ ├── layout_special_effects_selector_item.xml │ │ ├── layout_tadal_pat_record_prop.xml │ │ ├── layout_tidal_pat_filter.xml │ │ ├── seekbar_record.xml │ │ └── textview_seekhead.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── btn_cut_dis.png │ │ ├── btn_volume_nor.png │ │ ├── btn_volume_pre.png │ │ ├── chaopa_daojishi_zhihui.png │ │ ├── chaopai_luzhi_daojishi.png │ │ ├── chaopai_luzhi_daojishi_3.png │ │ ├── chaopai_luzhi_daojishi_6.png │ │ ├── chaopai_luzhi_daojishi_9.png │ │ ├── chaopai_xuanzhong.png │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ ├── tidal_pat_upload_cd_bg.png │ │ └── tidal_play_topic_icon.png │ │ ├── mipmap-xhdpi │ │ ├── bg_1.png │ │ ├── chao_yuan.png │ │ ├── chaopai_baihuati.png │ │ ├── chaopai_huatishangchu.png │ │ ├── chaopai_luzhi_daojishi.png │ │ ├── chaopai_luzhi_daojishi_3.png │ │ ├── chaopai_luzhi_daojishi_6.png │ │ ├── chaopai_luzhi_daojishi_9.png │ │ ├── chaopai_luzhi_fanhui.png │ │ ├── chaopai_luzhi_guangmeiyan.png │ │ ├── chaopai_luzhi_guanshanguangdeng.png │ │ ├── chaopai_luzhi_jiangtouqiehuan.png │ │ ├── chaopai_luzhi_jianyinyue.png │ │ ├── chaopai_luzhi_jianyinyuedian.png │ │ ├── chaopai_luzhi_kaimeiyan.png │ │ ├── chaopai_luzhi_kaishanguangdeng.png │ │ ├── chaopai_luzhi_lujing.png │ │ ├── chaopai_luzhi_shanchu.png │ │ ├── chaopai_luzhi_wancheng.png │ │ ├── chaopai_luzhi_wanchenmoren.png │ │ ├── chaopai_luzhi_wudaoju.png │ │ ├── chaopai_luzhi_xuanfengmian.png │ │ ├── chaopai_luzhi_xuanzhong.png │ │ ├── chaopai_play.png │ │ ├── chaopai_teixao.png │ │ ├── chaopai_teixao_nor.png │ │ ├── chaopai_yinliang.png │ │ ├── chaopai_yinyuebofang_icon.png │ │ ├── filter_background_original.png │ │ ├── filter_bw_03.png │ │ ├── filter_cf_17.png │ │ ├── filter_cf_19.png │ │ ├── filter_fm_05.png │ │ ├── filter_fm_10.png │ │ ├── filter_fs_10.png │ │ ├── filter_ins_02.png │ │ ├── filter_mod_09.png │ │ ├── filter_re_03.png │ │ ├── filter_sf_03.png │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ ├── icon_cigar.png │ │ ├── icon_glasses.png │ │ ├── icon_group1.png │ │ ├── icon_group2.png │ │ ├── icon_towel.png │ │ ├── run.png │ │ ├── se_soul_out.png │ │ ├── se_soul_out_selector.png │ │ ├── se_time_back.png │ │ ├── se_time_back_seletcor.png │ │ ├── se_un_state.png │ │ ├── se_un_state_selector.png │ │ └── shipinicon.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── raw │ │ ├── beauty.glsl │ │ ├── beep.ogg │ │ ├── default_fragment.glsl │ │ ├── default_vertex.glsl │ │ ├── gudie_video_one.mp4 │ │ └── lookup.glsl │ │ └── values │ │ ├── arrays.xml │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── tiktokdemo │ └── lky │ └── tiktokdemo │ └── ExampleUnitTest.java ├── build.gradle ├── gif ├── CropVideo.gif ├── RecordVideo.gif └── SpecialEffects.gif ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/libraries 5 | /.idea/modules.xml 6 | /.idea/workspace.xml 7 | .DS_Store 8 | /build 9 | /captures 10 | .externalNativeBuild 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TikTokDemo 2 | 仿抖音录制、特效处理、裁剪视频(也与微信裁剪视频类似) 3 | 4 | #### 仿抖音的一个Demo,包含美颜、滤镜、BGM裁剪、抖动特效和倒放等,以及裁剪视频等。 5 | 6 | #### `仅供参考`。 7 | 8 | 由于原本项目中功能比较复杂,只整理了部分,以及去除了不必要的功能。 9 | 10 | 没有用到原项目中的架构,只是做了简单整理,所以代码可能会比较糙。 11 | 12 | ### 以下是效果,gif可能有些大。 13 | 14 | ![录制](https://github.com/likaiyuan559/TikTokDemo/blob/master/gif/RecordVideo.gif) 15 | ![录制](https://github.com/likaiyuan559/TikTokDemo/blob/master/gif/SpecialEffects.gif) 16 | ![录制](https://github.com/likaiyuan559/TikTokDemo/blob/master/gif/CropVideo.gif) -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | defaultConfig { 6 | applicationId "com.tiktokdemo.lky.tiktokdemo" 7 | minSdkVersion 19 8 | targetSdkVersion 28 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | 13 | ndk { 14 | abiFilters "armeabi" 15 | // abiFilters "armeabi-v7a" 16 | } 17 | } 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | 25 | 26 | sourceSets { 27 | main { 28 | jniLibs.srcDirs = ['src/main/jniLibs'] 29 | jni.srcDirs = [] 30 | } 31 | } 32 | lintOptions { 33 | checkReleaseBuilds false 34 | abortOnError false 35 | } 36 | } 37 | 38 | dependencies { 39 | implementation fileTree(dir: 'libs', include: ['*.jar']) 40 | implementation 'com.android.support:appcompat-v7:28.0.0' 41 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 42 | testImplementation 'junit:junit:4.12' 43 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 44 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 45 | implementation 'com.android.support:recyclerview-v7:28.0.0' 46 | implementation files('libs/gson-2.2.2.jar') 47 | implementation files('libs/jna-min.jar') 48 | implementation 'org.greenrobot:eventbus:3.0.0' 49 | implementation 'com.github.bumptech.glide:glide:3.7.0' 50 | implementation 'jp.wasabeef:glide-transformations:2.0.1' 51 | implementation 'com.edmodo:cropper:1.0.1' 52 | implementation('com.kevin:crop:1.0.2') { 53 | // 如果已经引入 support:appcompat-v7 可以加上这句话 54 | exclude group: 'com.android.support', module: 'appcompat-v7' 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/libs/gson-2.2.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/libs/gson-2.2.2.jar -------------------------------------------------------------------------------- /app/libs/jna-min.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/libs/jna-min.jar -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/tiktokdemo/lky/tiktokdemo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest { 18 | 19 | @Test public void useAppContext() { 20 | // Context of the app under test. 21 | Context appContext = InstrumentationRegistry.getTargetContext(); 22 | 23 | assertEquals("com.tiktokdemo.lky.tiktokdemo", appContext.getPackageName()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 28 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | 40 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/assets/RBB.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/src/main/assets/RBB.mp4 -------------------------------------------------------------------------------- /app/src/main/assets/RISE.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/src/main/assets/RISE.mp3 -------------------------------------------------------------------------------- /app/src/main/java/com/heyhou/social/video/AudioListener.java: -------------------------------------------------------------------------------- 1 | package com.heyhou.social.video; 2 | 3 | /** 4 | * Created by Administrator on 2015/11/10 0010. 5 | */ 6 | 7 | public interface AudioListener { 8 | 9 | void onProgress(String outputPath, int percentage); 10 | void onComplete(String outputPath, short[] resampleBuffer); 11 | void onError(String outputPath, String error); 12 | } -------------------------------------------------------------------------------- /app/src/main/java/com/heyhou/social/video/FilterInfo.java: -------------------------------------------------------------------------------- 1 | package com.heyhou.social.video; 2 | 3 | /** 4 | * Created by starjiang on 17-6-21. 5 | */ 6 | 7 | public class FilterInfo { 8 | 9 | public final static int FILTER_SOUL_FADE_OUT = 1; 10 | 11 | private int filter; 12 | private long startTime; 13 | private long endTime; 14 | 15 | public int getFilter() { 16 | return filter; 17 | } 18 | 19 | public void setFilter(int filter) { 20 | this.filter = filter; 21 | } 22 | 23 | public long getStartTime() { 24 | return startTime; 25 | } 26 | 27 | public void setStartTime(long startTime) { 28 | this.startTime = startTime; 29 | } 30 | 31 | public long getEndTime() { 32 | return endTime; 33 | } 34 | 35 | public void setEndTime(long endTime) { 36 | this.endTime = endTime; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/heyhou/social/video/HeyhouAudio.java: -------------------------------------------------------------------------------- 1 | package com.heyhou.social.video; 2 | 3 | import java.util.ArrayList; 4 | 5 | /** 6 | * Created by DELL on 2017/8/17. 7 | */ 8 | 9 | public class HeyhouAudio { 10 | 11 | private static volatile HeyhouAudio instance = null; 12 | 13 | static { 14 | System.loadLibrary("openh264"); 15 | System.loadLibrary("ffmpeg"); 16 | System.loadLibrary("yuv"); 17 | System.loadLibrary("heyhou_video"); 18 | 19 | } 20 | 21 | public static HeyhouAudio getInstance(){ 22 | 23 | if(instance == null){ 24 | synchronized (HeyhouAudio.class){ 25 | if(instance == null){ 26 | instance = new HeyhouAudio(); 27 | } 28 | } 29 | } 30 | return instance; 31 | } 32 | 33 | protected HeyhouAudio(){ 34 | 35 | } 36 | 37 | /** 38 | * 加载bgm 39 | * @param audioPath 要加载的mp3 40 | * @param wavePath 输出的wav 文件 41 | * @param listener 回调 42 | * @return 0 成功,not 0 fail 43 | */ 44 | public native int audioRead(String audioPath, String wavePath, AudioListener listener); 45 | 46 | /** 47 | * 合成音乐 48 | * @param waveInfos 音轨文件信息数组 49 | * @param audioPath 要输出的文件 输出文件后缀为 aac 50 | */ 51 | public native int audioWrite(ArrayList waveInfos, String audioPath); 52 | 53 | /** 54 | * 剪切音乐 55 | * @param wavePath 56 | * @param starttime 剪切的开始时间 57 | * @param endtime 结束时间 58 | */ 59 | public native int audioCut(String wavePath, long starttime, long endtime); 60 | 61 | /** 62 | * 剪切音乐 63 | * @param wavePath 64 | * @param starttime 剪切的开始时间 65 | * @param endtime 结束时间 66 | */ 67 | public native int audioMove(String wavePath, String newWavePath, long starttime, long endtime, long newstarttime, long newendtime); 68 | 69 | /** 70 | * 录音初始化 71 | * @param wavePath 录音输出的文件路径 72 | */ 73 | public native int waveRecordInit(String wavePath); 74 | 75 | /** 76 | * 77 | * @param data audiorecorder录制的数据,采样双声道,16bit 采样 78 | * @param offset 录制音乐的起始位置 79 | * @param samples 采样个数 80 | * @return 81 | */ 82 | public native short[] waveRecord(byte []data,long offset,int samples); 83 | 84 | /** 85 | * 停止录制 86 | */ 87 | public native int waveRecordStop(); 88 | 89 | 90 | /** 91 | * 播放合成的音乐 92 | * @param waveInfos 93 | */ 94 | public native int wavePlayStart(ArrayList waveInfos, WavePlayListener listener); 95 | 96 | /** 97 | * 停止播放合成的音乐 98 | */ 99 | public native int wavePlayStop(); 100 | } 101 | -------------------------------------------------------------------------------- /app/src/main/java/com/heyhou/social/video/HeyhouPlayer.java: -------------------------------------------------------------------------------- 1 | package com.heyhou.social.video; 2 | 3 | import android.content.Context; 4 | import android.media.AudioTrack; 5 | import android.opengl.GLSurfaceView; 6 | 7 | /** 8 | * Created by Administrator on 2015/11/10 0010. 9 | */ 10 | public class HeyhouPlayer { 11 | static { 12 | 13 | System.loadLibrary("openh264"); 14 | System.loadLibrary("ffmpeg"); 15 | System.loadLibrary("yuv"); 16 | System.loadLibrary("heyhou_video"); 17 | 18 | } 19 | private Context context; 20 | private AudioTrack audioTrack = null; 21 | 22 | public HeyhouPlayer(Context context) 23 | { 24 | this.context = context; 25 | } 26 | 27 | /** 28 | * prepare media,when media start play MoListener.onPlay() will called 29 | * @param path play url 30 | *@return void 31 | */ 32 | public native void prepare(String path); 33 | 34 | /** 35 | * play the video 36 | */ 37 | public native void play(); 38 | 39 | /** 40 | * puase play, MoListener.onPause() will be called 41 | */ 42 | public native void pause(); 43 | 44 | /** 45 | * resume play,MoListener.onResume will be called 46 | */ 47 | public native void resume(); 48 | 49 | /** 50 | * stop play,MoListener.onStop() will be called 51 | */ 52 | public native void stop(); 53 | 54 | /** 55 | * @return true or false,only media is playing return value is true,or is false 56 | * 57 | */ 58 | public native boolean isPlaying(); 59 | 60 | // /** 61 | // * attach surface 62 | // * @param surface,render Surface,used by video output 63 | // */ 64 | // public native void attachSurface(Surface surface); 65 | // 66 | // /** 67 | // * detath surface 68 | // */ 69 | // public native void detachSurface(); 70 | 71 | 72 | /** 73 | * attach surface 74 | * @param render,render GLSurfaceView render,used by video output 75 | */ 76 | public native void attachRender(GLSurfaceView.Renderer render); 77 | 78 | /** 79 | * detath surface 80 | */ 81 | public native void detachRender(); 82 | 83 | /** 84 | * setListener,when play event happen,listener callback function will be called 85 | * @param listener 86 | */ 87 | public native void setListener(VideoPlayListener listener); 88 | 89 | /** 90 | * remove the listener 91 | */ 92 | public native void removeListener(); 93 | 94 | /** 95 | * check the media if can seekable 96 | * @return true or false,true can seekable,false can not seekable 97 | */ 98 | public native boolean isSeekable(); 99 | 100 | /** 101 | * set media posistion 102 | * @param position,time unit is micro second 103 | */ 104 | public native void setPosition(long position); 105 | 106 | /** 107 | * set media filter 108 | * @param filter 109 | */ 110 | public native void setFilter(int filter); 111 | 112 | /** 113 | * set media speed 114 | * @param speed 115 | */ 116 | public native void setSpeed(int speed); 117 | 118 | /** 119 | * get media current postion 120 | * @return media postion,time unit is microsecond 121 | */ 122 | public native long getPosition(); 123 | 124 | /** 125 | * get media current play time 126 | * @return time unit is micro second 127 | */ 128 | public native long getCurrentTime(); 129 | 130 | /** 131 | * get media duration 132 | * @return time unit is micro second 133 | */ 134 | public native long getDuration(); 135 | 136 | /** 137 | * set network buffering time 138 | * @param bufferTime time unit is millisecond 139 | */ 140 | public native void setBufferTime(long bufferTime); 141 | 142 | } 143 | -------------------------------------------------------------------------------- /app/src/main/java/com/heyhou/social/video/HeyhouVideo.java: -------------------------------------------------------------------------------- 1 | package com.heyhou.social.video; 2 | 3 | 4 | import java.util.ArrayList; 5 | 6 | import android.graphics.Bitmap; 7 | 8 | /** 9 | * Created by Administrator on 2015/11/10 0010. 10 | */ 11 | public class HeyhouVideo { 12 | static { 13 | System.loadLibrary("openh264"); 14 | System.loadLibrary("ffmpeg"); 15 | System.loadLibrary("yuv"); 16 | System.loadLibrary("heyhou_video"); 17 | 18 | } 19 | /** 20 | * combine video and audio to new video 21 | * @param videoInfos video list 22 | * @param audioPath audio path 23 | * @param weight1 video audio volume 24 | * @param weight2 audio volume 25 | * @param outputVideoPath output path 26 | *@return void 27 | */ 28 | public native void combine(ArrayList videoInfos, String audioPath, double weight1, double weight2, String outputVideoPath, VideoListener listener); 29 | 30 | 31 | /** 32 | * reverse video 33 | * @param videoPath video path 34 | * @param outPath output path 35 | * @param tmpPath frame tmp cache path must be a directory 36 | *@return void 37 | */ 38 | public native void reverse(String videoPath, String outPath, String tmpPath, VideoListener listener); 39 | 40 | 41 | /** 42 | * filter video 43 | * @param videoPath video path 44 | * @param outPath output path 45 | * @param filterinfos array 46 | *@return void 47 | */ 48 | public native void filter(String videoPath, ArrayList filterInfos, String outPath, VideoListener listener); 49 | 50 | /** 51 | * overlay video 52 | * @param videoPath video path 53 | * @param outPath output path 54 | * @param x video audio volume 55 | * @param y audio volume 56 | * @param overlayPath overlay file path 57 | *@return void 58 | */ 59 | public native void overlay(String videoPath, String outPath, String overlayPath, int x, int y, VideoListener listener); 60 | 61 | 62 | /** 63 | * get video frame 64 | * @param videoPath video path 65 | * @param seconds get the seconds frame 66 | * @param bitmap video frame bitmap 67 | *@return int 0 success not 0 fail 68 | */ 69 | public native void getFrameBitmap(String videoPath, long seconds, Bitmap bitmap, int rotate); 70 | 71 | 72 | 73 | /** 74 | * get video meta info 75 | * @param videoPath video path 76 | * @param metaInfo video frame bitmap 77 | *@return int 0 success not 0 fail 78 | */ 79 | public native void getMetaInfo(String videoPath, VideoMetaInfo metaInfo); 80 | 81 | 82 | /** 83 | * cut video 84 | * @param videoPath video path 85 | * @param outPath output path 86 | * @param starttime cut starttime 87 | * @param seconds need micro seconds 88 | * @param speed dst video speed 89 | *@return void 90 | */ 91 | public native void cutVideo(String videoPath, long starttime, long seconds, int speed, String outPath, VideoListener listener); 92 | 93 | /** 94 | * speed audio 95 | * @param audioPath audio path 96 | * @param speed audio speed -4 -2 1 2 4 97 | *@return void 98 | */ 99 | public native void speed(String audioPath, int speed, String outputPath, VideoListener listener); 100 | 101 | /** 102 | * cut audio 103 | * @param audioPath audio path 104 | * @param starttime audio starttime micro second 105 | * @param needtime audio needtime micro second 106 | *@return void 107 | */ 108 | public native void cut(String audioPath, long starttime, long needtime, String outputPath, VideoListener listener); 109 | 110 | } 111 | -------------------------------------------------------------------------------- /app/src/main/java/com/heyhou/social/video/Rotation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 CyberAgent 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.heyhou.social.video; 18 | 19 | public enum Rotation { 20 | NORMAL, ROTATION_90, ROTATION_180, ROTATION_270; 21 | 22 | /** 23 | * Retrieves the int representation of the Rotation. 24 | * 25 | * @return 0, 90, 180 or 270 26 | */ 27 | public int asInt() { 28 | switch (this) { 29 | case NORMAL: return 0; 30 | case ROTATION_90: return 90; 31 | case ROTATION_180: return 180; 32 | case ROTATION_270: return 270; 33 | default: throw new IllegalStateException("Unknown Rotation!"); 34 | } 35 | } 36 | 37 | /** 38 | * Create a Rotation from an integer. Needs to be either 0, 90, 180 or 270. 39 | * 40 | * @param rotation 0, 90, 180 or 270 41 | * @return Rotation object 42 | */ 43 | public static Rotation fromInt(int rotation) { 44 | switch (rotation) { 45 | case 0: return NORMAL; 46 | case 90: return ROTATION_90; 47 | case 180: return ROTATION_180; 48 | case 270: return ROTATION_270; 49 | case 360: return NORMAL; 50 | default: throw new IllegalStateException( 51 | rotation + " is an unknown rotation. Needs to be either 0, 90, 180 or 270!"); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/heyhou/social/video/TestRender.java: -------------------------------------------------------------------------------- 1 | package com.heyhou.social.video; 2 | 3 | import javax.microedition.khronos.egl.EGLConfig; 4 | import javax.microedition.khronos.opengles.GL10; 5 | 6 | import android.opengl.GLSurfaceView; 7 | 8 | 9 | /** 10 | * Created by lky on 2017/7/20. 11 | */ 12 | 13 | public class TestRender implements GLSurfaceView.Renderer { 14 | 15 | 16 | @Override 17 | public void onSurfaceCreated(GL10 gl, EGLConfig config) { 18 | 19 | } 20 | 21 | @Override 22 | public void onSurfaceChanged(GL10 gl, int width, int height) { 23 | 24 | } 25 | 26 | @Override 27 | public void onDrawFrame(GL10 gl) { 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/heyhou/social/video/TextureRotationUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 CyberAgent 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.heyhou.social.video; 18 | 19 | public class TextureRotationUtil { 20 | 21 | public static final float TEXTURE_NO_ROTATION[] = { 22 | 0.0f, 1.0f, 23 | 1.0f, 1.0f, 24 | 0.0f, 0.0f, 25 | 1.0f, 0.0f, 26 | }; 27 | 28 | public static final float TEXTURE_ROTATED_90[] = { 29 | 1.0f, 1.0f, 30 | 1.0f, 0.0f, 31 | 0.0f, 1.0f, 32 | 0.0f, 0.0f, 33 | }; 34 | public static final float TEXTURE_ROTATED_180[] = { 35 | 1.0f, 0.0f, 36 | 0.0f, 0.0f, 37 | 1.0f, 1.0f, 38 | 0.0f, 1.0f, 39 | }; 40 | public static final float TEXTURE_ROTATED_270[] = { 41 | 0.0f, 0.0f, 42 | 0.0f, 1.0f, 43 | 1.0f, 0.0f, 44 | 1.0f, 1.0f, 45 | }; 46 | 47 | public static final float CUBE[] = { 48 | -1.0f, -1.0f, 49 | 1.0f, -1.0f, 50 | -1.0f, 1.0f, 51 | 1.0f, 1.0f, 52 | }; 53 | 54 | private TextureRotationUtil() {} 55 | 56 | public static float[] getRotation(final Rotation rotation, final boolean flipHorizontal, final boolean flipVertical) { 57 | float[] rotatedTex; 58 | switch (rotation) { 59 | case ROTATION_90: 60 | rotatedTex = TEXTURE_ROTATED_90; 61 | break; 62 | case ROTATION_180: 63 | rotatedTex = TEXTURE_ROTATED_180; 64 | break; 65 | case ROTATION_270: 66 | rotatedTex = TEXTURE_ROTATED_270; 67 | break; 68 | case NORMAL: 69 | default: 70 | rotatedTex = TEXTURE_NO_ROTATION; 71 | break; 72 | } 73 | if (flipHorizontal) { 74 | rotatedTex = new float[]{ 75 | flip(rotatedTex[0]), rotatedTex[1], 76 | flip(rotatedTex[2]), rotatedTex[3], 77 | flip(rotatedTex[4]), rotatedTex[5], 78 | flip(rotatedTex[6]), rotatedTex[7], 79 | }; 80 | } 81 | if (flipVertical) { 82 | rotatedTex = new float[]{ 83 | rotatedTex[0], flip(rotatedTex[1]), 84 | rotatedTex[2], flip(rotatedTex[3]), 85 | rotatedTex[4], flip(rotatedTex[5]), 86 | rotatedTex[6], flip(rotatedTex[7]), 87 | }; 88 | } 89 | return rotatedTex; 90 | } 91 | 92 | 93 | private static float flip(final float i) { 94 | if (i == 0.0f) { 95 | return 1.0f; 96 | } 97 | return 0.0f; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /app/src/main/java/com/heyhou/social/video/VideoInfo.java: -------------------------------------------------------------------------------- 1 | package com.heyhou.social.video; 2 | 3 | /** 4 | * Created by starjiang on 12/8/16. 5 | */ 6 | 7 | public class VideoInfo { 8 | private String videoPath; 9 | private int times;//-4 -2 1 2 4 10 | 11 | public int getTimes() { 12 | return times; 13 | } 14 | 15 | public void setTimes(int times) { 16 | this.times = times; 17 | } 18 | 19 | public String getVideoPath() { 20 | return videoPath; 21 | } 22 | 23 | public void setVideoPath(String videoPath) { 24 | this.videoPath = videoPath; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/heyhou/social/video/VideoListener.java: -------------------------------------------------------------------------------- 1 | package com.heyhou.social.video; 2 | 3 | /** 4 | * Created by Administrator on 2015/11/10 0010. 5 | */ 6 | 7 | public interface VideoListener { 8 | 9 | void onProgress(String outputPath, int percentage); 10 | void onComplete(String outputPath); 11 | void onError(String outputPath, String error); 12 | } -------------------------------------------------------------------------------- /app/src/main/java/com/heyhou/social/video/VideoMetaInfo.java: -------------------------------------------------------------------------------- 1 | package com.heyhou.social.video; 2 | 3 | /** 4 | * Created by starjiang on 17-7-20. 5 | */ 6 | 7 | public class VideoMetaInfo { 8 | public long duration; 9 | public int width; 10 | public int height; 11 | public int rotation; 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/heyhou/social/video/VideoPlayListener.java: -------------------------------------------------------------------------------- 1 | package com.heyhou.social.video; 2 | 3 | /** 4 | * Created by Administrator on 2015/11/10 0010. 5 | */ 6 | 7 | public interface VideoPlayListener { 8 | 9 | /** 10 | * @param percentage buffering progress between 0-1 11 | */ 12 | public void onBufferingEvent(float percentage); 13 | 14 | public void onPrepareEvent(); 15 | /** 16 | * called when video playing, 17 | */ 18 | public void onPlayEvent(); 19 | 20 | public void onPauseEvent(); 21 | 22 | public void onResumeEvent(); 23 | 24 | public void onStopEvent(); 25 | 26 | /** 27 | * called when stream end 28 | */ 29 | public void onEndEvent(); 30 | 31 | /** 32 | * called when have error 33 | */ 34 | public void onErrorEvent(String msg); 35 | 36 | /** 37 | * 38 | * @param time current playing time,time unit:us 39 | */ 40 | public void onPlayTimeEvent(long time); 41 | 42 | } -------------------------------------------------------------------------------- /app/src/main/java/com/heyhou/social/video/VideoTimeType.java: -------------------------------------------------------------------------------- 1 | package com.heyhou.social.video; 2 | 3 | /** 4 | * Created by lky on 2016/12/9. 5 | */ 6 | 7 | public enum VideoTimeType { 8 | 9 | SPEED_M4(-3),//慢速4倍 10 | SPEED_M2(-2),//慢速2倍 11 | SPEED_N1(1),//正常速度 12 | SPEED_P2(2),//快速2倍 13 | SPEED_P4(3);//快速4倍 14 | 15 | private int value; 16 | 17 | public int getValue() { 18 | return value; 19 | } 20 | 21 | VideoTimeType(int value) { 22 | this.value = value; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/heyhou/social/video/WaveInfo.java: -------------------------------------------------------------------------------- 1 | package com.heyhou.social.video; 2 | 3 | /** 4 | * Created by DELL on 2017/8/21. 5 | */ 6 | 7 | public class WaveInfo { 8 | private String wavePath; 9 | private long startTime; 10 | private double volume; 11 | 12 | private long jump_start_time; 13 | private long jump_end_time; 14 | 15 | public long getStartTime() { 16 | return startTime; 17 | } 18 | 19 | public void setStartTime(long time) { 20 | this.startTime = time; 21 | } 22 | 23 | public double getVolume() { 24 | return volume; 25 | } 26 | 27 | public void setVolume(double volume) { 28 | this.volume = volume; 29 | } 30 | 31 | public String getWavePath() { 32 | return wavePath; 33 | } 34 | 35 | public void setWavePath(String path) { 36 | this.wavePath = path; 37 | } 38 | 39 | public long getJump_start_time() { 40 | return jump_start_time; 41 | } 42 | 43 | public void setJump_start_time(long time) { 44 | this.jump_start_time = time; 45 | } 46 | 47 | public long getJump_end_time() { 48 | return jump_end_time; 49 | } 50 | 51 | public void setJump_end_time(long time) { 52 | this.jump_end_time = time; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/heyhou/social/video/WavePlayListener.java: -------------------------------------------------------------------------------- 1 | package com.heyhou.social.video; 2 | 3 | /** 4 | * Created by DELL on 2017/8/31. 5 | */ 6 | 7 | public interface WavePlayListener { 8 | 9 | public void onPlayEvent(); 10 | 11 | public void onPauseEvent(); 12 | 13 | public void onResumeEvent(); 14 | 15 | public void onStopEvent(); 16 | 17 | public void onErrorEvent(String msg); 18 | 19 | public void onPlayTimeEvent(long time); 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/BaseApplication.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | /** 6 | * Created by lky on 2018/12/11 7 | */ 8 | public class BaseApplication extends Application { 9 | 10 | public static Context mContext; 11 | 12 | @Override public void onCreate() { 13 | super.onCreate(); 14 | mContext = this; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/Constant.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo; 2 | 3 | import java.io.File; 4 | 5 | import android.os.Environment; 6 | /** 7 | * Created by lky on 2018/12/11 8 | */ 9 | public class Constant { 10 | 11 | public static final String APP_LOCAL_DIR = File.separator + "lkyDemo"; 12 | public static final String PIC_FILE = Environment.getExternalStorageDirectory().getAbsolutePath() + APP_LOCAL_DIR; 13 | public static final String DIC_FILE = BaseApplication.mContext.getCacheDir().getAbsolutePath() + APP_LOCAL_DIR; 14 | 15 | public static final String RECORD_AUDIO_CACHE_PATH_TEMP = DIC_FILE + File.separator + "record_audio_cache"; 16 | public static final String IMAGE_SAVE_PATH = PIC_FILE + File.separator + "image"; 17 | public static final String RECORD_VIDEO_PATH_TEMP = DIC_FILE + File.separator + "record_video"; 18 | public static final String RECORD_VIDEO_PATH = PIC_FILE + File.separator + "record_video"; 19 | public static final String CUT_AUDIO_CACHE_PATH = PIC_FILE + File.separator + "cut"; 20 | public static final String RECORD_CROP_PHOTO_CACHE_PATH = DIC_FILE + File.separator + "record_crop"; 21 | public static final String RECORD_VIDEO_TEMP_PATH = PIC_FILE + File.separator + "record_video_temp"; 22 | public static final String SPEED_AUDIO_CACHE_PATH = DIC_FILE + File.separator + "speed_audio"; 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/HomeCallBack.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo; 2 | 3 | /** 4 | * Created by lky on 2016/10/28. 5 | */ 6 | 7 | public interface HomeCallBack { 8 | void finish(Object obj); 9 | void error(String errorStr); 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/adapter/TidalPatRecordPropAdapter.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.adapter; 2 | 3 | import java.util.ArrayList; 4 | 5 | import android.content.Context; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.ImageView; 11 | 12 | import com.tiktokdemo.lky.tiktokdemo.R; 13 | import com.tiktokdemo.lky.tiktokdemo.record.camera.widget.CommRecyclerViewHolder; 14 | import com.tiktokdemo.lky.tiktokdemo.record.helper.TidalPatPropFactory; 15 | import com.tiktokdemo.lky.tiktokdemo.record.helper.TidalPatPropType; 16 | 17 | /** 18 | * Created by lky on 2017/5/3. 19 | */ 20 | 21 | public class TidalPatRecordPropAdapter extends RecyclerView.Adapter { 22 | 23 | private ArrayList mTidalPatPropTypes; 24 | 25 | private OnPropItemClickListener mOnPropItemClickListener; 26 | 27 | public TidalPatRecordPropAdapter(ArrayList tidalPatPropTypes){ 28 | mTidalPatPropTypes = tidalPatPropTypes; 29 | } 30 | 31 | public void setOnPropItemClickListener(OnPropItemClickListener onPropItemClickListener) { 32 | mOnPropItemClickListener = onPropItemClickListener; 33 | } 34 | 35 | @Override 36 | public CommRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 37 | View view = LayoutInflater 38 | .from(parent.getContext()).inflate(R.layout.layout_tadal_pat_record_prop,parent,false); 39 | return new RecordPropViewHolder(parent.getContext(),view); 40 | } 41 | 42 | @Override 43 | public void onBindViewHolder(CommRecyclerViewHolder holder, int position) { 44 | bindViewHolder((RecordPropViewHolder) holder,position); 45 | } 46 | 47 | public void bindViewHolder(RecordPropViewHolder holder, final int position){ 48 | holder.mImageView.setImageResource(mTidalPatPropTypes.get(position).getBackgroundRes()); 49 | if(mTidalPatPropTypes.get(position) == TidalPatPropFactory.getInstance().getPropType()){ 50 | holder.mView.setVisibility(View.VISIBLE); 51 | }else{ 52 | holder.mView.setVisibility(View.GONE); 53 | } 54 | holder.itemView.setOnClickListener(new View.OnClickListener() { 55 | @Override 56 | public void onClick(View v) { 57 | if(mOnPropItemClickListener != null){ 58 | mOnPropItemClickListener.onPropItemClick(mTidalPatPropTypes.get(position)); 59 | } 60 | } 61 | }); 62 | } 63 | 64 | @Override 65 | public int getItemCount() { 66 | return mTidalPatPropTypes.size(); 67 | } 68 | 69 | public class RecordPropViewHolder extends CommRecyclerViewHolder{ 70 | 71 | public ImageView mImageView; 72 | public View mView; 73 | 74 | public RecordPropViewHolder(Context context, View itemView) { 75 | super(context, itemView); 76 | mImageView = getView(R.id.layout_tidal_pat_record_prop_img); 77 | mView = getView(R.id.layout_tidal_pat_record_prop_view); 78 | } 79 | } 80 | 81 | public interface OnPropItemClickListener{ 82 | void onPropItemClick(TidalPatPropType tidalPatPropType); 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/bean/LyricSignRangeInfo.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.bean; 2 | 3 | import java.io.Serializable; 4 | 5 | import android.graphics.Color; 6 | 7 | /** 8 | * Created by lky on 2017/8/15. 9 | */ 10 | 11 | public class LyricSignRangeInfo implements Serializable { 12 | 13 | private int mFrom; 14 | private int mTo; 15 | private int mTextColor; 16 | 17 | public LyricSignRangeInfo(int from, int to) { 18 | this.mFrom = from; 19 | this.mTo = to; 20 | this.mTextColor = Color.WHITE; 21 | } 22 | public LyricSignRangeInfo(int from, int to, int textColor) { 23 | this.mFrom = from; 24 | this.mTo = to; 25 | this.mTextColor = textColor; 26 | } 27 | 28 | public boolean isWrappedBy(int start, int end) { 29 | return (start > mFrom && start < mTo) || (end > mFrom && end < mTo); 30 | } 31 | 32 | public boolean contains(int start, int end) { 33 | return mFrom < start && mTo >= end; 34 | } 35 | 36 | public boolean isEqual(int start, int end) { 37 | return (mFrom == start && mTo == end) || (mFrom == end && mTo == start); 38 | } 39 | 40 | public int getAnchorPosition(int value) { 41 | if ((value - mFrom) - (mTo - value) >= 0) { 42 | return mTo; 43 | } else { 44 | return mFrom; 45 | } 46 | } 47 | 48 | public int getFrom() { 49 | return mFrom; 50 | } 51 | 52 | public Integer getFromInteger(){ 53 | return mFrom; 54 | } 55 | 56 | public int getTo() { 57 | return mTo; 58 | } 59 | 60 | public Integer getToInteger(){ 61 | return mTo; 62 | } 63 | 64 | public int getTextColor() { 65 | return mTextColor; 66 | } 67 | 68 | public void setFrom(int from) { 69 | mFrom = from; 70 | } 71 | 72 | public void setTo(int to) { 73 | mTo = to; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/bean/MusicBean.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.bean; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Created by 1 on 2017/4/25. 7 | */ 8 | public class MusicBean implements Serializable { 9 | private int musicId; 10 | private String name; 11 | private String cover; 12 | private String author; 13 | private int useTimesVirtual; 14 | private int formatDuration; 15 | private String url; 16 | private boolean isFav; 17 | private boolean isSelected; 18 | private boolean isPlaying; 19 | private boolean isDownloading; 20 | private String localPath; 21 | private String detailUrl; 22 | private String actName; 23 | 24 | 25 | public String getDetailUrl() { 26 | return detailUrl; 27 | } 28 | 29 | public void setDetailUrl(String detailUrl) { 30 | this.detailUrl = detailUrl; 31 | } 32 | 33 | public String getLocalPath() { 34 | return localPath; 35 | } 36 | 37 | public void setLocalPath(String localPath) { 38 | this.localPath = localPath; 39 | } 40 | 41 | public boolean isDownloading() { 42 | return isDownloading; 43 | } 44 | 45 | public void setIsDownloading(boolean isDownloading) { 46 | this.isDownloading = isDownloading; 47 | } 48 | 49 | public boolean isPlaying() { 50 | return isPlaying; 51 | } 52 | 53 | public void setIsPlaying(boolean isPlaying) { 54 | this.isPlaying = isPlaying; 55 | } 56 | 57 | public void setIsSelected(boolean isSelected) { 58 | this.isSelected = isSelected; 59 | } 60 | 61 | public boolean isSelected() { 62 | return isSelected; 63 | } 64 | 65 | public int getMusicId() { 66 | return musicId; 67 | } 68 | 69 | public void setMusicId(int musicId) { 70 | this.musicId = musicId; 71 | } 72 | 73 | public boolean isFav() { 74 | return isFav; 75 | } 76 | 77 | public void setIsFav(boolean isFav) { 78 | this.isFav = isFav; 79 | } 80 | 81 | public String getUrl() { 82 | return url; 83 | } 84 | 85 | public void setUrl(String url) { 86 | this.url = url; 87 | } 88 | 89 | public int getFormatDuration() { 90 | return formatDuration; 91 | } 92 | 93 | public int getFormatDurationInSecond() { 94 | return formatDuration / 1000; 95 | } 96 | 97 | public void setFormatDuration(int formatDuration) { 98 | this.formatDuration = formatDuration; 99 | } 100 | 101 | public String getAuthor() { 102 | return author; 103 | } 104 | 105 | public void setAuthor(String author) { 106 | this.author = author; 107 | } 108 | 109 | public String getCover() { 110 | return cover; 111 | } 112 | 113 | public void setCover(String cover) { 114 | this.cover = cover; 115 | } 116 | 117 | public String getName() { 118 | return name; 119 | } 120 | 121 | public void setName(String name) { 122 | this.name = name; 123 | } 124 | 125 | public int getUseTimesVirtual() { 126 | return useTimesVirtual; 127 | } 128 | 129 | public void setUseTimesVirtual(int useTimesVirtual) { 130 | this.useTimesVirtual = useTimesVirtual; 131 | } 132 | 133 | public void setActName(String actName) { 134 | this.actName = actName; 135 | } 136 | 137 | public String getActName() { 138 | return actName; 139 | } 140 | 141 | public MusicBean toCollectBean() { 142 | MusicBean bean = new MusicBean(); 143 | bean.setIsSelected(false); 144 | bean.setIsPlaying(false); 145 | bean.setAuthor(author); 146 | bean.setMusicId(musicId); 147 | bean.setName(name); 148 | bean.setCover(cover); 149 | bean.setFormatDuration(formatDuration); 150 | bean.setIsFav(true); 151 | bean.setUrl(url); 152 | bean.setUseTimesVirtual(useTimesVirtual); 153 | return bean; 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/bean/RecordStudioUploadEvent.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.bean; 2 | 3 | /** 4 | * Created by ydc on 2017/9/1. 5 | */ 6 | public class RecordStudioUploadEvent { 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/bean/RecordingDemoBean.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.bean; 2 | 3 | /** 4 | * Created by lky on 2018/1/8. 5 | */ 6 | 7 | public class RecordingDemoBean { 8 | 9 | private String userId; 10 | private String mBGMPath; 11 | private String mBGMLoadPath; 12 | private String mAudioTrackPath; 13 | private long mDuration; 14 | private String mAudioName; 15 | private String mLyricStr; 16 | private long mRecordDuration; 17 | 18 | private int mMusicId; 19 | private String mMusicCover; 20 | private String mCombinePath; 21 | private long mCreateTime; 22 | 23 | private String actName; 24 | 25 | public void setUserId(String userId) { 26 | this.userId = userId; 27 | } 28 | 29 | public void setBGMPath(String BGMPath) { 30 | mBGMPath = BGMPath; 31 | } 32 | 33 | public void setBGMLoadPath(String BGMLoadPath) { 34 | mBGMLoadPath = BGMLoadPath; 35 | } 36 | 37 | public void setAudioTrackPath(String audioTrackPath) { 38 | mAudioTrackPath = audioTrackPath; 39 | } 40 | 41 | public void setDuration(long duration) { 42 | mDuration = duration; 43 | } 44 | 45 | public void setAudioName(String audioName) { 46 | mAudioName = audioName; 47 | } 48 | 49 | 50 | public void setLyricStr(String lyricStr) { 51 | mLyricStr = lyricStr; 52 | } 53 | 54 | public void setRecordDuration(long recordDuration) { 55 | mRecordDuration = recordDuration; 56 | } 57 | 58 | public void setMusicId(int musicId) { 59 | mMusicId = musicId; 60 | } 61 | 62 | public void setMusicCover(String musicCover) { 63 | mMusicCover = musicCover; 64 | } 65 | 66 | public void setCombinePath(String combinePath) { 67 | mCombinePath = combinePath; 68 | } 69 | 70 | public void setCreateTime(long createTime) { 71 | mCreateTime = createTime; 72 | } 73 | 74 | public String getUserId() { 75 | return userId; 76 | } 77 | 78 | public String getBGMPath() { 79 | return mBGMPath; 80 | } 81 | 82 | public String getBGMLoadPath() { 83 | return mBGMLoadPath; 84 | } 85 | 86 | public String getAudioTrackPath() { 87 | return mAudioTrackPath; 88 | } 89 | 90 | public long getDuration() { 91 | return mDuration; 92 | } 93 | 94 | public String getAudioName() { 95 | return mAudioName; 96 | } 97 | 98 | public String getLyricStr() { 99 | return mLyricStr; 100 | } 101 | 102 | public long getRecordDuration() { 103 | return mRecordDuration; 104 | } 105 | 106 | public int getMusicId() { 107 | return mMusicId; 108 | } 109 | 110 | public String getMusicCover() { 111 | return mMusicCover; 112 | } 113 | 114 | public String getCombinePath() { 115 | return mCombinePath; 116 | } 117 | 118 | public long getCreateTime() { 119 | return mCreateTime; 120 | } 121 | 122 | public void setActName(String actName) { 123 | this.actName = actName; 124 | } 125 | 126 | public String getActName() { 127 | return actName; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/bean/SpecialEffectsParentType.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.bean; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Created by lky on 2017/6/27. 7 | */ 8 | 9 | public enum SpecialEffectsParentType implements Serializable { 10 | FILTER, 11 | TIME, 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/bean/SpecialEffectsProgressBean.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.bean; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Created by lky on 2017/6/21. 7 | */ 8 | 9 | public class SpecialEffectsProgressBean implements Serializable { 10 | private SpecialEffectsType mType; 11 | private int mShowColor; 12 | private long mTimeStart; 13 | private long mTimeEnd; 14 | 15 | public void setType(SpecialEffectsType type) { 16 | mType = type; 17 | } 18 | 19 | public void setShowColor(int showColor) { 20 | mShowColor = showColor; 21 | } 22 | 23 | public void setTimeStart(long timeStart) { 24 | mTimeStart = timeStart; 25 | } 26 | 27 | public void setTimeEnd(long timeEnd) { 28 | mTimeEnd = timeEnd; 29 | } 30 | 31 | public SpecialEffectsType getType() { 32 | return mType; 33 | } 34 | 35 | public int getShowColor() { 36 | return mShowColor; 37 | } 38 | 39 | public long getTimeStart() { 40 | return mTimeStart; 41 | } 42 | 43 | public long getTimeEnd() { 44 | return mTimeEnd; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/bean/SpecialEffectsType.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.bean; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Created by lky on 2017/6/21. 7 | */ 8 | 9 | public enum SpecialEffectsType implements Serializable { 10 | SoulOut(1), 11 | Shake(0), 12 | Default(0), 13 | TimeBack(0); 14 | 15 | private int filter; 16 | 17 | SpecialEffectsType(int filter) { 18 | this.filter = filter; 19 | } 20 | 21 | public int getFilter() { 22 | return filter; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/bean/TidalPatRecordFilterInfo.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.bean; 2 | 3 | /** 4 | * Created by lky on 2017/4/28. 5 | */ 6 | 7 | public class TidalPatRecordFilterInfo { 8 | 9 | private int mBackgroundRes; 10 | private String mFilterName; 11 | private int mFilterRes; 12 | 13 | public TidalPatRecordFilterInfo(int backgroundRes, String filterName, int filterRes) { 14 | mBackgroundRes = backgroundRes; 15 | mFilterName = filterName; 16 | mFilterRes = filterRes; 17 | } 18 | 19 | public void setBackgroundRes(int backgroundRes) { 20 | mBackgroundRes = backgroundRes; 21 | } 22 | 23 | public void setFilterName(String filterName) { 24 | mFilterName = filterName; 25 | } 26 | 27 | public void setFilterRes(int filterRes) { 28 | mFilterRes = filterRes; 29 | } 30 | 31 | public int getBackgroundRes() { 32 | return mBackgroundRes; 33 | } 34 | 35 | public String getFilterName() { 36 | return mFilterName; 37 | } 38 | 39 | public int getFilterRes() { 40 | return mFilterRes; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/bean/TidalPatUploadEvent.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.bean; 2 | 3 | /** 4 | * Created by lky on 2017/6/13. 5 | */ 6 | 7 | public class TidalPatUploadEvent { 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/bean/TidalPatUploadFinishEvent.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.bean; 2 | 3 | /** 4 | * Created by lky on 2017/6/19. 5 | */ 6 | 7 | public class TidalPatUploadFinishEvent { 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/bean/VideoFrameBean.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.bean; 2 | 3 | import android.graphics.Bitmap; 4 | 5 | /** 6 | * Created by lky on 2017/7/17. 7 | */ 8 | 9 | public class VideoFrameBean { 10 | 11 | private VideoFrameBean mPrev; 12 | 13 | private VideoFrameBean mNext; 14 | 15 | private Bitmap mBitmap; 16 | 17 | private long mFrameTime; 18 | 19 | 20 | public void setPrev(VideoFrameBean prev) { 21 | mPrev = prev; 22 | } 23 | 24 | public VideoFrameBean prev() { 25 | return mPrev; 26 | } 27 | 28 | public void setNext(VideoFrameBean next) { 29 | mNext = next; 30 | } 31 | 32 | public VideoFrameBean next() { 33 | return mNext; 34 | } 35 | 36 | public void setBitmap(Bitmap bitmap) { 37 | mBitmap = bitmap; 38 | } 39 | 40 | public void setFrameTime(long frameTime) { 41 | mFrameTime = frameTime; 42 | } 43 | 44 | public Bitmap getBitmap() { 45 | return mBitmap; 46 | } 47 | 48 | public long getFrameTime() { 49 | return mFrameTime; 50 | } 51 | 52 | public boolean isValid(){ 53 | return mBitmap != null && !mBitmap.isRecycled(); 54 | } 55 | 56 | @Override 57 | public String toString() { 58 | return "VideoFrameBean{" + 59 | "mFrameTime=" + mFrameTime + 60 | '}'; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/bean/VoiceFrequencyInfo.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.bean; 2 | 3 | import java.io.Serializable; 4 | 5 | import android.graphics.Path; 6 | 7 | /** 8 | * Created by lky on 2017/8/21. 9 | */ 10 | 11 | public class VoiceFrequencyInfo implements Serializable { 12 | 13 | private final int MIN_CAPACITY_INCREMENT = 6; 14 | 15 | private long mStartPosition; 16 | private long mEndPosition; 17 | private long mPositionSize; 18 | private short[] mAudioData; 19 | private transient Path mPath; 20 | 21 | public VoiceFrequencyInfo() { 22 | mAudioData = new short[0]; 23 | } 24 | 25 | public VoiceFrequencyInfo(long startPosition, long endPosition) { 26 | mStartPosition = startPosition; 27 | mEndPosition = endPosition; 28 | mPositionSize = mEndPosition - mStartPosition; 29 | mAudioData = new short[0]; 30 | } 31 | 32 | public void setStartPosition(long startPosition) { 33 | mStartPosition = startPosition; 34 | } 35 | 36 | public void setEndPosition(long endPosition) { 37 | mEndPosition = endPosition; 38 | } 39 | 40 | public void setPositionSize(long positionSize) { 41 | mPositionSize = positionSize; 42 | } 43 | 44 | public Long getStartPositionFromLong() { 45 | return mStartPosition; 46 | } 47 | 48 | public long getStartPosition() { 49 | return mStartPosition; 50 | } 51 | 52 | public long getEndPosition() { 53 | return mEndPosition; 54 | } 55 | 56 | public long getPositionSize() { 57 | return mPositionSize; 58 | } 59 | 60 | public void setPath(Path path) { 61 | mPath = path; 62 | } 63 | 64 | public Path getPath() { 65 | return mPath; 66 | } 67 | 68 | public void setAudioData(short[] audioData) { 69 | mAudioData = audioData; 70 | size = mAudioData.length; 71 | } 72 | 73 | public short[] getAudioData() { 74 | return mAudioData; 75 | } 76 | 77 | private int size; 78 | 79 | public void addData(short[] data){ 80 | int newPartSize = data.length; 81 | if (newPartSize == 0) { 82 | return ; 83 | } 84 | short[] a = mAudioData; 85 | int s = size; 86 | int newSize = s + newPartSize; // If add overflows, arraycopy will fail 87 | if (newSize > a.length) { 88 | int newCapacity = newCapacity(newSize - 1); // ~33% growth room 89 | short[] newArray = new short[newCapacity]; 90 | System.arraycopy(a, 0, newArray, 0, s); 91 | mAudioData = a = newArray; 92 | } 93 | System.arraycopy(data, 0, a, s, newPartSize); 94 | size = newSize; 95 | } 96 | 97 | // public void addDataFromMagnify(short[] data){ 98 | // int newPartSize = data.length; 99 | // if (newPartSize == 0) { 100 | // return ; 101 | // } 102 | // short[] a = mAudioData; 103 | // int s = mAudioData.length; 104 | // short[] newArray = new short[mAudioData.length + data.length]; 105 | // System.arraycopy(a, 0, newArray, 0, s); 106 | // mAudioData = a = newArray; 107 | // System.arraycopy(data, 0, a, s, newPartSize); 108 | // size = mAudioData.length; 109 | // } 110 | 111 | public int getDataSize(){ 112 | return size; 113 | } 114 | 115 | private int newCapacity(int currentCapacity) { 116 | int increment = (currentCapacity < (MIN_CAPACITY_INCREMENT / 2) ? 117 | MIN_CAPACITY_INCREMENT : currentCapacity >> 1); 118 | return currentCapacity + increment; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/beautify/MagicJni.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.camera.beautify; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | import android.graphics.Bitmap; 6 | 7 | /** 8 | * Created by why8222 on 2016/2/29. 9 | */ 10 | public class MagicJni { 11 | static{ 12 | System.loadLibrary("hh_magic_camera"); 13 | } 14 | 15 | public static native void jniInitMagicBeautify(ByteBuffer handler); 16 | public static native void jniUnInitMagicBeautify(); 17 | 18 | public static native void jniStartSkinSmooth(float denoiseLevel); 19 | public static native void jniStartWhiteSkin(float whitenLevel); 20 | 21 | public static native ByteBuffer jniStoreBitmapData(Bitmap bitmap); 22 | public static native void jniFreeBitmapData(ByteBuffer handler); 23 | public static native Bitmap jniGetBitmapFromStoredBitmapData(ByteBuffer handler); 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/camera/utils/CameraInfo.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.camera.camera.utils; 2 | 3 | /** 4 | * Created by why8222 on 2016/2/25. 5 | */ 6 | public class CameraInfo { 7 | 8 | public int previewWidth; 9 | 10 | public int previewHeight; 11 | 12 | public int orientation; 13 | 14 | public boolean isFront; 15 | 16 | public int pictureWidth; 17 | 18 | public int pictureHeight; 19 | 20 | public String flashMode; 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/camera/utils/CameraUtils.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.camera.camera.utils; 2 | 3 | import java.util.List; 4 | 5 | import android.hardware.Camera; 6 | 7 | /** 8 | * Created by why8222 on 2016/2/25. 9 | */ 10 | public class CameraUtils { 11 | 12 | public static Camera.Size getLargePictureSize(Camera camera){ 13 | if(camera != null){ 14 | List sizes = camera.getParameters().getSupportedPictureSizes(); 15 | Camera.Size temp = sizes.get(0); 16 | for(int i = 1;i < sizes.size();i ++){ 17 | float scale = (float)(sizes.get(i).height) / sizes.get(i).width; 18 | if(temp.width < sizes.get(i).width && scale < 0.6f && scale > 0.5f) 19 | temp = sizes.get(i); 20 | } 21 | return temp; 22 | } 23 | return null; 24 | } 25 | 26 | public static Camera.Size getLargePreviewSize(Camera camera){ 27 | if(camera != null){ 28 | List sizes = camera.getParameters().getSupportedPreviewSizes(); 29 | Camera.Size temp = sizes.get(0); 30 | for(int i = 1;i < sizes.size();i ++){ 31 | if(temp.width < sizes.get(i).width) 32 | temp = sizes.get(i); 33 | } 34 | return temp; 35 | } 36 | return null; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/encoder/video/WindowSurface.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Google Inc. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tiktokdemo.lky.tiktokdemo.record.camera.encoder.video; 18 | 19 | import android.graphics.SurfaceTexture; 20 | import android.view.Surface; 21 | 22 | import com.tiktokdemo.lky.tiktokdemo.record.camera.encoder.gles.EglCore; 23 | import com.tiktokdemo.lky.tiktokdemo.record.camera.encoder.gles.EglSurfaceBase; 24 | 25 | 26 | /** 27 | * Recordable EGL window surface. 28 | *

29 | * It's good practice to explicitly release() the surface, preferably from a "finally" block. 30 | */ 31 | public class WindowSurface extends EglSurfaceBase { 32 | private Surface mSurface; 33 | private boolean mReleaseSurface; 34 | 35 | /** 36 | * Associates an EGL surface with the native window surface. 37 | *

38 | * Set releaseSurface to true if you want the Surface to be released when release() is 39 | * called. This is convenient, but can interfere with framework classes that expect to 40 | * manage the Surface themselves (e.g. if you release a SurfaceView's Surface, the 41 | * surfaceDestroyed() callback won't fire). 42 | */ 43 | public WindowSurface(EglCore eglCore, Surface surface, boolean releaseSurface) { 44 | super(eglCore); 45 | createWindowSurface(surface); 46 | mSurface = surface; 47 | mReleaseSurface = releaseSurface; 48 | } 49 | 50 | /** 51 | * Associates an EGL surface with the SurfaceTexture. 52 | */ 53 | public WindowSurface(EglCore eglCore, SurfaceTexture surfaceTexture) { 54 | super(eglCore); 55 | createWindowSurface(surfaceTexture); 56 | } 57 | 58 | /** 59 | * Releases any resources associated with the EGL surface (and, if configured to do so, 60 | * with the Surface as well). 61 | *

62 | * Does not require that the surface's EGL context be current. 63 | */ 64 | public void release() { 65 | releaseEglSurface(); 66 | if (mSurface != null) { 67 | if (mReleaseSurface) { 68 | mSurface.release(); 69 | } 70 | mSurface = null; 71 | } 72 | } 73 | 74 | /** 75 | * Recreate the EGLSurface, using the new EglBase. The caller should have already 76 | * freed the old EGLSurface with releaseEglSurface(). 77 | *

78 | * This is useful when we want to update the EGLSurface associated with a Surface. 79 | * For example, if we want to share with a different EGLContext, which can only 80 | * be done by tearing down and recreating the context. (That's handled by the caller; 81 | * this just creates a new EGLSurface for the Surface we were handed earlier.) 82 | *

83 | * If the previous EGLSurface isn't fully destroyed, e.g. it's still current on a 84 | * context somewhere, the create call will fail with complaints from the Surface 85 | * about already being connected. 86 | */ 87 | public void recreate(EglCore newEglCore) { 88 | if (mSurface == null) { 89 | throw new RuntimeException("not yet implemented for SurfaceTexture"); 90 | } 91 | mEglCore = newEglCore; // switch to new context 92 | createWindowSurface(mSurface); // create new surface 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/filter/base/MagicLookupFilter.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.camera.filter.base; 2 | 3 | import android.opengl.GLES20; 4 | 5 | import com.tiktokdemo.lky.tiktokdemo.record.camera.filter.base.gpuimage.GPUImageFilter; 6 | import com.tiktokdemo.lky.tiktokdemo.record.camera.utils.MagicParams; 7 | import com.tiktokdemo.lky.tiktokdemo.record.camera.utils.OpenGlUtils; 8 | 9 | 10 | public class MagicLookupFilter extends GPUImageFilter { 11 | 12 | public static final String LOOKUP_FRAGMENT_SHADER = ""+ 13 | "varying highp vec2 textureCoordinate;\n" + 14 | " \n" + 15 | " uniform sampler2D inputImageTexture;\n" + 16 | " uniform sampler2D inputImageTexture2; // lookup texture\n" + 17 | " \n" + 18 | " void main()\n" + 19 | " {\n" + 20 | " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + 21 | " \n" + 22 | " mediump float blueColor = textureColor.b * 63.0;\n" + 23 | " \n" + 24 | " mediump vec2 quad1;\n" + 25 | " quad1.y = floor(floor(blueColor) / 8.0);\n" + 26 | " quad1.x = floor(blueColor) - (quad1.y * 8.0);\n" + 27 | " \n" + 28 | " mediump vec2 quad2;\n" + 29 | " quad2.y = floor(ceil(blueColor) / 8.0);\n" + 30 | " quad2.x = ceil(blueColor) - (quad2.y * 8.0);\n" + 31 | " \n" + 32 | " highp vec2 texPos1;\n" + 33 | " texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);\n" + 34 | " texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);\n" + 35 | " \n" + 36 | " highp vec2 texPos2;\n" + 37 | " texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);\n" + 38 | " texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);\n" + 39 | " \n" + 40 | " lowp vec4 newColor1 = texture2D(inputImageTexture2, texPos1);\n" + 41 | " lowp vec4 newColor2 = texture2D(inputImageTexture2, texPos2);\n" + 42 | " \n" + 43 | " lowp vec4 newColor = mix(newColor1, newColor2, fract(blueColor));\n" + 44 | " gl_FragColor = vec4(newColor.rgb, textureColor.w);\n" + 45 | " }"; 46 | 47 | protected String table; 48 | 49 | public MagicLookupFilter(String table) { 50 | super(NO_FILTER_VERTEX_SHADER,LOOKUP_FRAGMENT_SHADER); 51 | this.table = table; 52 | } 53 | 54 | public int mLookupTextureUniform; 55 | public int mLookupSourceTexture = OpenGlUtils.NO_TEXTURE; 56 | 57 | protected void onInit(){ 58 | super.onInit(); 59 | mLookupTextureUniform = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture2"); 60 | } 61 | 62 | protected void onInitialized(){ 63 | super.onInitialized(); 64 | runOnDraw(new Runnable(){ 65 | public void run(){ 66 | mLookupSourceTexture = OpenGlUtils.loadTexture(MagicParams.context, table); 67 | } 68 | }); 69 | } 70 | 71 | protected void onDestroy(){ 72 | super.onDestroy(); 73 | int[] texture = new int[]{mLookupSourceTexture}; 74 | GLES20.glDeleteTextures(1, texture, 0); 75 | mLookupSourceTexture = -1; 76 | } 77 | 78 | protected void onDrawArraysAfter(){ 79 | if (mLookupSourceTexture != -1){ 80 | GLES20.glActiveTexture(GLES20.GL_TEXTURE3); 81 | GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); 82 | GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 83 | } 84 | } 85 | 86 | protected void onDrawArraysPre(){ 87 | if (mLookupSourceTexture != -1){ 88 | GLES20.glActiveTexture(GLES20.GL_TEXTURE3); 89 | GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mLookupSourceTexture); 90 | GLES20.glUniform1i(mLookupTextureUniform, 3); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/filter/base/gpuimage/GPUImageBrightnessFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 CyberAgent 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tiktokdemo.lky.tiktokdemo.record.camera.filter.base.gpuimage; 18 | 19 | import android.opengl.GLES20; 20 | 21 | /** 22 | * brightness value ranges from -1.0 to 1.0, with 0.0 as the normal level 23 | */ 24 | public class GPUImageBrightnessFilter extends GPUImageFilter { 25 | public static final String BRIGHTNESS_FRAGMENT_SHADER = "" + 26 | "varying highp vec2 textureCoordinate;\n" + 27 | " \n" + 28 | " uniform sampler2D inputImageTexture;\n" + 29 | " uniform lowp float brightness;\n" + 30 | " \n" + 31 | " void main()\n" + 32 | " {\n" + 33 | " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + 34 | " \n" + 35 | " gl_FragColor = vec4((textureColor.rgb + vec3(brightness)), textureColor.w);\n" + 36 | " }"; 37 | 38 | private int mBrightnessLocation; 39 | private float mBrightness; 40 | 41 | public GPUImageBrightnessFilter() { 42 | this(0.0f); 43 | } 44 | 45 | public GPUImageBrightnessFilter(final float brightness) { 46 | super(NO_FILTER_VERTEX_SHADER, BRIGHTNESS_FRAGMENT_SHADER); 47 | mBrightness = brightness; 48 | } 49 | 50 | @Override 51 | public void onInit() { 52 | super.onInit(); 53 | mBrightnessLocation = GLES20.glGetUniformLocation(getProgram(), "brightness"); 54 | } 55 | 56 | @Override 57 | public void onInitialized() { 58 | super.onInitialized(); 59 | setBrightness(mBrightness); 60 | } 61 | 62 | public void setBrightness(final float brightness) { 63 | mBrightness = brightness; 64 | setFloat(mBrightnessLocation, mBrightness); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/filter/base/gpuimage/GPUImageContrastFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 CyberAgent 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tiktokdemo.lky.tiktokdemo.record.camera.filter.base.gpuimage; 18 | 19 | import android.opengl.GLES20; 20 | 21 | /** 22 | * Changes the contrast of the image.
23 | *
24 | * contrast value ranges from 0.0 to 4.0, with 1.0 as the normal level 25 | */ 26 | public class GPUImageContrastFilter extends GPUImageFilter { 27 | public static final String CONTRAST_FRAGMENT_SHADER = "" + 28 | "varying highp vec2 textureCoordinate;\n" + 29 | " \n" + 30 | " uniform sampler2D inputImageTexture;\n" + 31 | " uniform lowp float contrast;\n" + 32 | " \n" + 33 | " void main()\n" + 34 | " {\n" + 35 | " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + 36 | " \n" + 37 | " gl_FragColor = vec4(((textureColor.rgb - vec3(0.5)) * contrast + vec3(0.5)), textureColor.w);\n" + 38 | " }"; 39 | 40 | private int mContrastLocation; 41 | private float mContrast; 42 | 43 | public GPUImageContrastFilter() { 44 | this(1.0f); 45 | } 46 | 47 | public GPUImageContrastFilter(float contrast) { 48 | super(NO_FILTER_VERTEX_SHADER, CONTRAST_FRAGMENT_SHADER); 49 | mContrast = contrast; 50 | } 51 | 52 | @Override 53 | public void onInit() { 54 | super.onInit(); 55 | mContrastLocation = GLES20.glGetUniformLocation(getProgram(), "contrast"); 56 | } 57 | 58 | @Override 59 | public void onInitialized() { 60 | super.onInitialized(); 61 | setContrast(mContrast); 62 | } 63 | 64 | public void setContrast(final float contrast) { 65 | mContrast = contrast; 66 | setFloat(mContrastLocation, mContrast); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/filter/base/gpuimage/GPUImageExposureFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 CyberAgent 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tiktokdemo.lky.tiktokdemo.record.camera.filter.base.gpuimage; 18 | 19 | import android.opengl.GLES20; 20 | 21 | /** 22 | * exposure: The adjusted exposure (-10.0 - 10.0, with 0.0 as the default) 23 | */ 24 | public class GPUImageExposureFilter extends GPUImageFilter { 25 | public static final String EXPOSURE_FRAGMENT_SHADER = "" + 26 | " varying highp vec2 textureCoordinate;\n" + 27 | " \n" + 28 | " uniform sampler2D inputImageTexture;\n" + 29 | " uniform highp float exposure;\n" + 30 | " \n" + 31 | " void main()\n" + 32 | " {\n" + 33 | " highp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + 34 | " \n" + 35 | " gl_FragColor = vec4(textureColor.rgb * pow(2.0, exposure), textureColor.w);\n" + 36 | " } "; 37 | 38 | private int mExposureLocation; 39 | private float mExposure; 40 | 41 | public GPUImageExposureFilter() { 42 | this(0.0f); 43 | } 44 | 45 | public GPUImageExposureFilter(final float exposure) { 46 | super(NO_FILTER_VERTEX_SHADER, EXPOSURE_FRAGMENT_SHADER); 47 | mExposure = exposure; 48 | } 49 | 50 | @Override 51 | public void onInit() { 52 | super.onInit(); 53 | mExposureLocation = GLES20.glGetUniformLocation(getProgram(), "exposure"); 54 | } 55 | 56 | @Override 57 | public void onInitialized() { 58 | super.onInitialized(); 59 | setExposure(mExposure); 60 | } 61 | 62 | public void setExposure(final float exposure) { 63 | mExposure = exposure; 64 | setFloat(mExposureLocation, mExposure); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/filter/base/gpuimage/GPUImageHueFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 CyberAgent 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tiktokdemo.lky.tiktokdemo.record.camera.filter.base.gpuimage; 18 | 19 | import android.opengl.GLES20; 20 | 21 | public class GPUImageHueFilter extends GPUImageFilter { 22 | public static final String HUE_FRAGMENT_SHADER = "" + 23 | "precision highp float;\n" + 24 | "varying highp vec2 textureCoordinate;\n" + 25 | "\n" + 26 | "uniform sampler2D inputImageTexture;\n" + 27 | "uniform mediump float hueAdjust;\n" + 28 | "const highp vec4 kRGBToYPrime = vec4 (0.299, 0.587, 0.114, 0.0);\n" + 29 | "const highp vec4 kRGBToI = vec4 (0.595716, -0.274453, -0.321263, 0.0);\n" + 30 | "const highp vec4 kRGBToQ = vec4 (0.211456, -0.522591, 0.31135, 0.0);\n" + 31 | "\n" + 32 | "const highp vec4 kYIQToR = vec4 (1.0, 0.9563, 0.6210, 0.0);\n" + 33 | "const highp vec4 kYIQToG = vec4 (1.0, -0.2721, -0.6474, 0.0);\n" + 34 | "const highp vec4 kYIQToB = vec4 (1.0, -1.1070, 1.7046, 0.0);\n" + 35 | "\n" + 36 | "void main ()\n" + 37 | "{\n" + 38 | " // Sample the input pixel\n" + 39 | " highp vec4 color = texture2D(inputImageTexture, textureCoordinate);\n" + 40 | "\n" + 41 | " // Convert to YIQ\n" + 42 | " highp float YPrime = dot (color, kRGBToYPrime);\n" + 43 | " highp float I = dot (color, kRGBToI);\n" + 44 | " highp float Q = dot (color, kRGBToQ);\n" + 45 | "\n" + 46 | " // Calculate the hue and chroma\n" + 47 | " highp float hue = atan (Q, I);\n" + 48 | " highp float chroma = sqrt (I * I + Q * Q);\n" + 49 | "\n" + 50 | " // Make the user's adjustments\n" + 51 | " hue += (-hueAdjust); //why negative rotation?\n" + 52 | "\n" + 53 | " // Convert back to YIQ\n" + 54 | " Q = chroma * sin (hue);\n" + 55 | " I = chroma * cos (hue);\n" + 56 | "\n" + 57 | " // Convert back to RGB\n" + 58 | " highp vec4 yIQ = vec4 (YPrime, I, Q, 0.0);\n" + 59 | " color.r = dot (yIQ, kYIQToR);\n" + 60 | " color.g = dot (yIQ, kYIQToG);\n" + 61 | " color.b = dot (yIQ, kYIQToB);\n" + 62 | "\n" + 63 | " // Save the result\n" + 64 | " gl_FragColor = color;\n" + 65 | "}\n"; 66 | 67 | private float mHue; 68 | private int mHueLocation; 69 | 70 | public GPUImageHueFilter() { 71 | this(0.0f); 72 | } 73 | 74 | public GPUImageHueFilter(final float hue) { 75 | super(NO_FILTER_VERTEX_SHADER, HUE_FRAGMENT_SHADER); 76 | mHue = hue; 77 | } 78 | 79 | @Override 80 | public void onInit() { 81 | super.onInit(); 82 | mHueLocation = GLES20.glGetUniformLocation(getProgram(), "hueAdjust"); 83 | } 84 | 85 | @Override 86 | public void onInitialized() { 87 | super.onInitialized(); 88 | setHue(mHue); 89 | } 90 | 91 | public void setHue(final float hue) { 92 | mHue = hue; 93 | float hueAdjust = (mHue % 360.0f) * (float) Math.PI / 180.0f; 94 | setFloat(mHueLocation, hueAdjust); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/filter/base/gpuimage/GPUImageLookupFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 CyberAgent 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tiktokdemo.lky.tiktokdemo.record.camera.filter.base.gpuimage; 18 | 19 | import com.tiktokdemo.lky.tiktokdemo.R; 20 | import com.tiktokdemo.lky.tiktokdemo.record.camera.utils.OpenGlUtils; 21 | 22 | public class GPUImageLookupFilter extends GPUImageTwoInputFilter { 23 | 24 | public static final String LOOKUP_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + 25 | " varying highp vec2 textureCoordinate2; // TODO: This is not used\n" + 26 | " \n" + 27 | " uniform sampler2D inputImageTexture;\n" + 28 | " uniform sampler2D inputImageTexture2; // lookup texture\n" + 29 | " \n" + 30 | " void main()\n" + 31 | " {\n" + 32 | " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + 33 | " \n" + 34 | " mediump float blueColor = textureColor.b * 63.0;\n" + 35 | " \n" + 36 | " mediump vec2 quad1;\n" + 37 | " quad1.y = floor(floor(blueColor) / 8.0);\n" + 38 | " quad1.x = floor(blueColor) - (quad1.y * 8.0);\n" + 39 | " \n" + 40 | " mediump vec2 quad2;\n" + 41 | " quad2.y = floor(ceil(blueColor) / 8.0);\n" + 42 | " quad2.x = ceil(blueColor) - (quad2.y * 8.0);\n" + 43 | " \n" + 44 | " highp vec2 texPos1;\n" + 45 | " texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);\n" + 46 | " texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);\n" + 47 | " \n" + 48 | " highp vec2 texPos2;\n" + 49 | " texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);\n" + 50 | " texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);\n" + 51 | " \n" + 52 | " lowp vec4 newColor1 = texture2D(inputImageTexture2, texPos1);\n" + 53 | " lowp vec4 newColor2 = texture2D(inputImageTexture2, texPos2);\n" + 54 | " \n" + 55 | " lowp vec4 newColor = mix(newColor1, newColor2, fract(blueColor));\n" + 56 | " gl_FragColor = vec4(newColor.rgb, textureColor.w);" + 57 | " gl_FragColor = vec4(gl_FragColor.rgb * pow(2.0, -0.3), textureColor.w);\n" + 58 | " }"; 59 | 60 | 61 | public GPUImageLookupFilter() { 62 | super(OpenGlUtils.readShaderFromRawResource(R.raw.lookup)); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/filter/base/gpuimage/GPUImageMiniLookupFilter.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.camera.filter.base.gpuimage; 2 | 3 | /** 4 | * Created by lky on 2017/5/19. 5 | */ 6 | 7 | public class GPUImageMiniLookupFilter extends GPUImageTwoInputFilter { 8 | 9 | public static final String LOOKUP_FRAGMENT_SHADER = 10 | " varying highp vec2 textureCoordinate;\n" + 11 | " varying highp vec2 textureCoordinate2; // TODO: This is not used\n" + 12 | " \n" + 13 | " uniform sampler2D inputImageTexture;\n" + 14 | " uniform sampler2D inputImageTexture2; // lookup texture\n" + 15 | " \n" + 16 | " void main()\n" + 17 | " {\n" + 18 | " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + 19 | " \n" + 20 | " mediump float blueColor = textureColor.b * 15.0;\n" + 21 | " \n" + 22 | " mediump vec2 quad1;\n" + 23 | " quad1.y = floor(floor(blueColor) / 2.0);\n" + 24 | " quad1.x = floor(blueColor) - (quad1.y * 2.0);\n" + 25 | " \n" + 26 | " mediump vec2 quad2;\n" + 27 | " quad2.y = floor(ceil(blueColor) / 2.0);\n" + 28 | " quad2.x = ceil(blueColor) - (quad2.y * 2.0);\n" + 29 | " \n" + 30 | " highp vec2 texPos1;\n" + 31 | " texPos1.x = (quad1.x * 0.03125) + 0.125/64.0 + ((0.03125 - 0.25/64.0) * textureColor.r);\n" + 32 | " texPos1.y = (quad1.y * 0.03125) + 0.125/64.0 + ((0.03125 - 0.25/64.0) * textureColor.g);\n" + 33 | " \n" + 34 | " highp vec2 texPos2;\n" + 35 | " texPos2.x = (quad2.x * 0.03125) + 0.125/64.0 + ((0.03125 - 0.25/64.0) * textureColor.r);\n" + 36 | " texPos2.y = (quad2.y * 0.03125) + 0.125/64.0 + ((0.03125 - 0.25/64.0) * textureColor.g);\n" + 37 | " \n" + 38 | " lowp vec4 newColor1 = texture2D(inputImageTexture2, texPos1);\n" + 39 | " lowp vec4 newColor2 = texture2D(inputImageTexture2, texPos2);\n" + 40 | " \n" + 41 | " lowp vec4 newColor = mix(newColor1, newColor2, fract(blueColor));\n" + 42 | " gl_FragColor = vec4(newColor.rgb, textureColor.w);\n" + 43 | " }"; 44 | 45 | 46 | public GPUImageMiniLookupFilter() { 47 | super(LOOKUP_FRAGMENT_SHADER); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/filter/base/gpuimage/GPUImageOverlayBlendFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 CyberAgent 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tiktokdemo.lky.tiktokdemo.record.camera.filter.base.gpuimage; 18 | public class GPUImageOverlayBlendFilter extends GPUImageTwoInputFilter { 19 | public static final String OVERLAY_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + 20 | " varying highp vec2 textureCoordinate2;\n" + 21 | "\n" + 22 | " uniform sampler2D inputImageTexture;\n" + 23 | " uniform sampler2D inputImageTexture2;\n" + 24 | " \n" + 25 | " void main()\n" + 26 | " {\n" + 27 | " mediump vec4 base = texture2D(inputImageTexture, textureCoordinate);\n" + 28 | " mediump vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);\n" + 29 | " \n" + 30 | " mediump float ra;\n" + 31 | " if (2.0 * base.r < base.a) {\n" + 32 | " ra = 2.0 * overlay.r * base.r + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);\n" + 33 | " } else {\n" + 34 | " ra = overlay.a * base.a - 2.0 * (base.a - base.r) * (overlay.a - overlay.r) + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);\n" + 35 | " }\n" + 36 | " \n" + 37 | " mediump float ga;\n" + 38 | " if (2.0 * base.g < base.a) {\n" + 39 | " ga = 2.0 * overlay.g * base.g + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);\n" + 40 | " } else {\n" + 41 | " ga = overlay.a * base.a - 2.0 * (base.a - base.g) * (overlay.a - overlay.g) + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);\n" + 42 | " }\n" + 43 | " \n" + 44 | " mediump float ba;\n" + 45 | " if (2.0 * base.b < base.a) {\n" + 46 | " ba = 2.0 * overlay.b * base.b + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);\n" + 47 | " } else {\n" + 48 | " ba = overlay.a * base.a - 2.0 * (base.a - base.b) * (overlay.a - overlay.b) + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);\n" + 49 | " }\n" + 50 | " \n" + 51 | " gl_FragColor = vec4(ra, ga, ba, 1.0);\n" + 52 | " }"; 53 | 54 | public GPUImageOverlayBlendFilter() { 55 | super(OVERLAY_BLEND_FRAGMENT_SHADER); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/filter/base/gpuimage/GPUImageSaturationFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 CyberAgent 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.tiktokdemo.lky.tiktokdemo.record.camera.filter.base.gpuimage; 18 | 19 | import android.opengl.GLES20; 20 | 21 | /** 22 | * saturation: The degree of saturation or desaturation to apply to the image (0.0 - 2.0, with 1.0 as the default) 23 | */ 24 | public class GPUImageSaturationFilter extends GPUImageFilter { 25 | public static final String SATURATION_FRAGMENT_SHADER = "" + 26 | " varying highp vec2 textureCoordinate;\n" + 27 | " \n" + 28 | " uniform sampler2D inputImageTexture;\n" + 29 | " uniform lowp float saturation;\n" + 30 | " \n" + 31 | " // Values from \"Graphics Shaders: Theory and Practice\" by Bailey and Cunningham\n" + 32 | " const mediump vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721);\n" + 33 | " \n" + 34 | " void main()\n" + 35 | " {\n" + 36 | " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + 37 | " lowp float luminance = dot(textureColor.rgb, luminanceWeighting);\n" + 38 | " lowp vec3 greyScaleColor = vec3(luminance);\n" + 39 | " \n" + 40 | " gl_FragColor = vec4(mix(greyScaleColor, textureColor.rgb, saturation), textureColor.w);\n" + 41 | " \n" + 42 | " }"; 43 | 44 | private int mSaturationLocation; 45 | private float mSaturation; 46 | 47 | public GPUImageSaturationFilter() { 48 | this(1.0f); 49 | } 50 | 51 | public GPUImageSaturationFilter(final float saturation) { 52 | super(NO_FILTER_VERTEX_SHADER, SATURATION_FRAGMENT_SHADER); 53 | mSaturation = saturation; 54 | } 55 | 56 | @Override 57 | public void onInit() { 58 | super.onInit(); 59 | mSaturationLocation = GLES20.glGetUniformLocation(getProgram(), "saturation"); 60 | } 61 | 62 | @Override 63 | public void onInitialized() { 64 | super.onInitialized(); 65 | setSaturation(mSaturation); 66 | } 67 | 68 | public void setSaturation(final float saturation) { 69 | mSaturation = saturation; 70 | setFloat(mSaturationLocation, mSaturation); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/filter/base/gpuimage/MagicBeautyFilter.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.camera.filter.base.gpuimage; 2 | 3 | import android.opengl.GLES20; 4 | 5 | import com.tiktokdemo.lky.tiktokdemo.R; 6 | import com.tiktokdemo.lky.tiktokdemo.record.camera.utils.MagicParams; 7 | import com.tiktokdemo.lky.tiktokdemo.record.camera.utils.OpenGlUtils; 8 | 9 | 10 | /** 11 | * Created by Administrator on 2016/5/22. 12 | */ 13 | public class MagicBeautyFilter extends GPUImageFilter{ 14 | private int mSingleStepOffsetLocation; 15 | private int mParamsLocation; 16 | 17 | public MagicBeautyFilter(){ 18 | super(NO_FILTER_VERTEX_SHADER , 19 | OpenGlUtils.readShaderFromRawResource(R.raw.beauty)); 20 | } 21 | 22 | protected void onInit() { 23 | super.onInit(); 24 | mSingleStepOffsetLocation = GLES20.glGetUniformLocation(getProgram(), "singleStepOffset"); 25 | mParamsLocation = GLES20.glGetUniformLocation(getProgram(), "params"); 26 | setBeautyLevel(MagicParams.beautyLevel); 27 | } 28 | 29 | private void setTexelSize(final float w, final float h) { 30 | setFloatVec2(mSingleStepOffsetLocation, new float[] {2.0f / w, 2.0f / h}); 31 | } 32 | 33 | @Override 34 | public void onInputSizeChanged(final int width, final int height) { 35 | super.onInputSizeChanged(width, height); 36 | setTexelSize(width, height); 37 | } 38 | 39 | public void setBeautyLevel(int level){ 40 | switch (level) { 41 | case 1: 42 | setFloat(mParamsLocation, 1.0f); 43 | break; 44 | case 2: 45 | setFloat(mParamsLocation, 0.8f); 46 | break; 47 | case 3: 48 | setFloat(mParamsLocation,0.6f); 49 | break; 50 | case 4: 51 | setFloat(mParamsLocation, 0.4f); 52 | break; 53 | case 5: 54 | setFloat(mParamsLocation,0.33f); 55 | break; 56 | default: 57 | break; 58 | } 59 | } 60 | 61 | public void onBeautyLevelChanged(){ 62 | setBeautyLevel(MagicParams.beautyLevel); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/filter/helper/FilterInfo.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.camera.filter.helper; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by lky on 2017/4/25. 7 | */ 8 | 9 | public class FilterInfo { 10 | 11 | 12 | /** 13 | * type : 0 14 | * scaleWidth : 12 15 | * scaleHight : 0 16 | * offsetX : 0.5 17 | * offsetY : 0.8 18 | * alignIndexes : [15,19,2] 19 | * folder : smoking 20 | * frames : 11 21 | * frameDuration : 110 22 | * width : 400 23 | * height : 249 24 | * triggerType : 1 25 | */ 26 | 27 | private int type; 28 | private float scaleWidth; 29 | private float scaleHight; 30 | private float offsetX; 31 | private float offsetY; 32 | private String folder; 33 | private int frames; 34 | private int frameDuration; 35 | private int width; 36 | private int height; 37 | private int triggerType; 38 | private List alignIndexes; 39 | 40 | public int getType() { 41 | return type; 42 | } 43 | 44 | public void setType(int type) { 45 | this.type = type; 46 | } 47 | 48 | public float getScaleWidth() { 49 | return scaleWidth; 50 | } 51 | 52 | public void setScaleWidth(float scaleWidth) { 53 | this.scaleWidth = scaleWidth; 54 | } 55 | 56 | public float getScaleHight() { 57 | return scaleHight; 58 | } 59 | 60 | public void setScaleHight(float scaleHight) { 61 | this.scaleHight = scaleHight; 62 | } 63 | 64 | public float getOffsetX() { 65 | return offsetX; 66 | } 67 | 68 | public void setOffsetX(float offsetX) { 69 | this.offsetX = offsetX; 70 | } 71 | 72 | public float getOffsetY() { 73 | return offsetY; 74 | } 75 | 76 | public void setOffsetY(float offsetY) { 77 | this.offsetY = offsetY; 78 | } 79 | 80 | public String getFolder() { 81 | return folder; 82 | } 83 | 84 | public void setFolder(String folder) { 85 | this.folder = folder; 86 | } 87 | 88 | public int getFrames() { 89 | return frames; 90 | } 91 | 92 | public void setFrames(int frames) { 93 | this.frames = frames; 94 | } 95 | 96 | public int getFrameDuration() { 97 | return frameDuration; 98 | } 99 | 100 | public void setFrameDuration(int frameDuration) { 101 | this.frameDuration = frameDuration; 102 | } 103 | 104 | public int getWidth() { 105 | return width; 106 | } 107 | 108 | public void setWidth(int width) { 109 | this.width = width; 110 | } 111 | 112 | public int getHeight() { 113 | return height; 114 | } 115 | 116 | public void setHeight(int height) { 117 | this.height = height; 118 | } 119 | 120 | public int getTriggerType() { 121 | return triggerType; 122 | } 123 | 124 | public void setTriggerType(int triggerType) { 125 | this.triggerType = triggerType; 126 | } 127 | 128 | public List getAlignIndexes() { 129 | return alignIndexes; 130 | } 131 | 132 | public void setAlignIndexes(List alignIndexes) { 133 | this.alignIndexes = alignIndexes; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/filter/helper/MagicFilterType.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.camera.filter.helper; 2 | 3 | /** 4 | * Created by why8222 on 2016/2/25. 5 | */ 6 | public enum MagicFilterType { 7 | NONE, 8 | FAIRYTALE, 9 | SUNRISE, 10 | SUNSET, 11 | WHITECAT, 12 | BLACKCAT, 13 | SKINWHITEN, 14 | HEALTHY, 15 | SWEETS, 16 | ROMANCE, 17 | SAKURA, 18 | WARM, 19 | ANTIQUE, 20 | NOSTALGIA, 21 | CALM, 22 | LATTE, 23 | TENDER, 24 | COOL, 25 | EMERALD, 26 | EVERGREEN, 27 | CRAYON, 28 | SKETCH, 29 | AMARO, 30 | BRANNAN, 31 | BROOKLYN, 32 | EARLYBIRD, 33 | FREUD, 34 | HEFE, 35 | HUDSON, 36 | INKWELL, 37 | KEVIN, 38 | LOMO, 39 | N1977, 40 | NASHVILLE, 41 | PIXAR, 42 | RISE, 43 | SIERRA, 44 | SUTRO, 45 | TOASTER2, 46 | VALENCIA, 47 | WALDEN, 48 | XPROII, 49 | //image adjust 50 | CONTRAST, 51 | BRIGHTNESS, 52 | EXPOSURE, 53 | HUE, 54 | SATURATION, 55 | SHARPEN, 56 | IMAGE_ADJUST 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/filter/helper/MagicPropFactory.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.camera.filter.helper; 2 | 3 | /** 4 | * Created by lky on 2017/4/24. 5 | */ 6 | 7 | public class MagicPropFactory { 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/filter/prop/PropDynamicFilter.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.camera.filter.prop; 2 | 3 | import java.util.ArrayList; 4 | 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.graphics.PointF; 8 | import android.opengl.GLES20; 9 | import android.os.SystemClock; 10 | 11 | import com.tiktokdemo.lky.tiktokdemo.BaseApplication; 12 | import com.tiktokdemo.lky.tiktokdemo.record.camera.filter.base.gpuimage.GPUImageNormalBlendFilter; 13 | import com.tiktokdemo.lky.tiktokdemo.record.camera.filter.helper.FilterInfo; 14 | import com.tiktokdemo.lky.tiktokdemo.record.camera.utils.OpenGlUtils; 15 | import com.tiktokdemo.lky.tiktokdemo.record.camera.utils.PointParseUtil; 16 | 17 | /** 18 | * Created by lky on 2017/4/24. 19 | */ 20 | 21 | public class PropDynamicFilter extends GPUImageNormalBlendFilter { 22 | 23 | 24 | private ArrayList mBitmaps; 25 | private int mCurrentBitmapPosition; 26 | private FilterInfo mFilterInfo; 27 | private boolean isKill; 28 | 29 | public PropDynamicFilter(int[] res, final FilterInfo filterInfo){ 30 | mBitmaps = new ArrayList<>(); 31 | for(int i=0;i= mBitmaps.size()){ 50 | mCurrentBitmapPosition = 0; 51 | } 52 | setBitmap(mBitmaps.get(mCurrentBitmapPosition)); 53 | } 54 | } 55 | }).start(); 56 | } 57 | 58 | @Override 59 | public void setBitmap(final Bitmap bitmap) { 60 | if (bitmap != null && bitmap.isRecycled()) { 61 | return; 62 | } 63 | mBitmap = bitmap; 64 | if (mBitmap == null) { 65 | return; 66 | } 67 | runOnDraw(new Runnable() { 68 | public void run() { 69 | if (bitmap == null || bitmap.isRecycled()) { 70 | return; 71 | } 72 | GLES20.glActiveTexture(GLES20.GL_TEXTURE3); 73 | mFilterSourceTexture2 = OpenGlUtils 74 | .loadTexture(bitmap, OpenGlUtils.NO_TEXTURE, false); 75 | } 76 | }); 77 | } 78 | 79 | @Override 80 | public void onDestroy() { 81 | super.onDestroy(); 82 | if(mBitmaps != null){ 83 | mBitmaps.clear(); 84 | mBitmaps = null; 85 | } 86 | isKill = true; 87 | } 88 | 89 | public void setFacePosition(int width,int height,PointF[] pointFs){ 90 | float[] array = PointParseUtil.parseCoordinatesData(width,height,pointFs,mFilterInfo); 91 | setFilterSecondTextureCoordinateAttribute(array); 92 | } 93 | 94 | 95 | } 96 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/helper/SavePictureTask.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.camera.helper; 2 | 3 | import java.io.File; 4 | import java.io.FileNotFoundException; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | 8 | import android.graphics.Bitmap; 9 | import android.media.MediaScannerConnection; 10 | import android.net.Uri; 11 | import android.os.AsyncTask; 12 | 13 | import com.tiktokdemo.lky.tiktokdemo.record.camera.utils.MagicParams; 14 | 15 | 16 | public class SavePictureTask extends AsyncTask { 17 | 18 | private OnPictureSaveListener onPictureSaveListener; 19 | private File file; 20 | 21 | public SavePictureTask(File file, OnPictureSaveListener listener){ 22 | this.onPictureSaveListener = listener; 23 | this.file = file; 24 | } 25 | 26 | @Override 27 | protected void onPreExecute() { 28 | super.onPreExecute(); 29 | } 30 | 31 | @Override 32 | protected void onPostExecute(final String result) { 33 | if(result != null) 34 | MediaScannerConnection.scanFile(MagicParams.context, 35 | new String[] {result}, null, 36 | new MediaScannerConnection.OnScanCompletedListener() { 37 | @Override 38 | public void onScanCompleted(final String path, final Uri uri) { 39 | if (onPictureSaveListener != null) 40 | onPictureSaveListener.onSaved(result); 41 | } 42 | }); 43 | } 44 | 45 | @Override 46 | protected String doInBackground(Bitmap... params) { 47 | if(file == null) 48 | return null; 49 | return saveBitmap(params[0]); 50 | } 51 | 52 | private String saveBitmap(Bitmap bitmap) { 53 | if (file.exists()) { 54 | file.delete(); 55 | } 56 | try { 57 | FileOutputStream out = new FileOutputStream(file); 58 | bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out); 59 | out.flush(); 60 | out.close(); 61 | bitmap.recycle(); 62 | return file.toString(); 63 | } catch (FileNotFoundException e) { 64 | e.printStackTrace(); 65 | } catch (IOException e) { 66 | e.printStackTrace(); 67 | } 68 | return null; 69 | } 70 | 71 | public interface OnPictureSaveListener{ 72 | void onSaved(String result); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/stmobileapi/STImageFormat.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.camera.stmobileapi; 2 | 3 | public class STImageFormat { 4 | public static final int ST_PIX_FMT_GRAY8 = 0; 5 | public static final int ST_PIX_FMT_YUV420P = 1; 6 | public static final int ST_PIX_FMT_NV12 = 2; 7 | public static final int ST_PIX_FMT_NV21 = 3; 8 | public static final int ST_PIX_FMT_BGRA8888 = 4; 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/stmobileapi/STMobile106.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.camera.stmobileapi; 2 | 3 | import android.graphics.PointF; 4 | import android.graphics.Rect; 5 | 6 | 7 | /** 8 | * STMobile API: StMobile 9 | * Created by Guangli W on 9/7/15. 10 | */ 11 | public class STMobile106 extends STMobileApiBridge.st_mobile_106_t { 12 | 13 | public STMobile106() { 14 | } 15 | 16 | /** 17 | * Get face Rect 18 | * @return Rect 19 | */ 20 | public Rect getRect() { 21 | Rect r = new Rect(); 22 | r.bottom = rect.bottom; 23 | r.top = rect.top; 24 | r.left = rect.left; 25 | r.right = rect.right; 26 | return r; 27 | } 28 | 29 | /** 30 | * Get face Points Array 31 | * @return Points Array, please check the length of array 32 | */ 33 | public PointF[] getPointsArray() { 34 | PointF[] ans = new PointF[106]; 35 | for (int i = 0; i < 106; i++) { 36 | ans[i] = new PointF(); 37 | ans[i].x = points_array[2 * i]; 38 | ans[i].y = points_array[2 * i + 1]; 39 | } 40 | return ans; 41 | } 42 | 43 | public STMobile106(STMobileApiBridge.st_mobile_106_t origin) { 44 | rect.bottom = origin.rect.bottom; 45 | rect.top = origin.rect.top; 46 | rect.left = origin.rect.left; 47 | rect.right = origin.rect.right; 48 | 49 | score = origin.score; 50 | yaw = origin.yaw; 51 | pitch = origin.pitch; 52 | roll = origin.roll; 53 | eye_dist = origin.eye_dist; 54 | ID = origin.ID; 55 | 56 | for (int i = 0; i < points_array.length; i++) { 57 | points_array[i] = origin.points_array[i]; 58 | } 59 | } 60 | 61 | @Override 62 | public String toString() { 63 | return "STMobile(" + getRect() + ", " + score + ")"; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/stmobileapi/STMobileFaceAction.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.camera.stmobileapi; 2 | 3 | 4 | /** 5 | * Created by zhym on 2016/8/23. 6 | */ 7 | 8 | public class STMobileFaceAction extends STMobileApiBridge.st_mobile_face_action_t { 9 | public STMobileFaceAction() { 10 | } 11 | 12 | public STMobileFaceAction(STMobileApiBridge.st_mobile_face_action_t origin) { 13 | face.rect = origin.face.rect; 14 | face.score = origin.face.score; 15 | face.yaw = origin.face.yaw; 16 | face.pitch = origin.face.pitch; 17 | face.roll = origin.face.roll; 18 | face.eye_dist = origin.face.eye_dist; 19 | face.ID = origin.face.ID; 20 | 21 | for(int i=0; i mViews; 19 | private Context mContext; 20 | private View mConvertView; 21 | 22 | 23 | public CommRecyclerViewHolder(Context context, View itemView) { 24 | super(itemView); 25 | mContext = context; 26 | mConvertView = itemView; 27 | mViews = new SparseArray(); 28 | } 29 | 30 | public CommRecyclerViewHolder(Context context, View itemView, ViewGroup parent) { 31 | super(itemView); 32 | mContext = context; 33 | mConvertView = itemView; 34 | mViews = new SparseArray<>(); 35 | } 36 | 37 | public static CommRecyclerViewHolder get(Context context, View itemView) { 38 | CommRecyclerViewHolder holder = new CommRecyclerViewHolder(context, itemView); 39 | return holder; 40 | } 41 | 42 | 43 | public static CommRecyclerViewHolder get(Context context, ViewGroup parent, int layoutId) { 44 | View itemView = LayoutInflater.from(context).inflate(layoutId, parent, false); 45 | CommRecyclerViewHolder viewHolder = new CommRecyclerViewHolder(context, itemView, parent); 46 | return viewHolder; 47 | } 48 | 49 | public View getmConvertView() { 50 | return mConvertView; 51 | } 52 | 53 | public Context getContext() { 54 | return mContext; 55 | } 56 | 57 | public T getView(int viewId) { 58 | View view = mViews.get(viewId); 59 | if (view == null) { 60 | view = mConvertView.findViewById(viewId); 61 | mViews.put(viewId, view); 62 | } 63 | return (T) view; 64 | } 65 | 66 | 67 | public CommRecyclerViewHolder setText(int viewId, String text) { 68 | TextView tv = getView(viewId); 69 | tv.setText(text); 70 | return this; 71 | } 72 | 73 | public CommRecyclerViewHolder setImageResource(int viewId, int resId) { 74 | ImageView view = getView(viewId); 75 | view.setImageResource(resId); 76 | return this; 77 | } 78 | 79 | public CommRecyclerViewHolder setOnClickListener(int viewId, 80 | View.OnClickListener listener) { 81 | View view = getView(viewId); 82 | view.setOnClickListener(listener); 83 | return this; 84 | } 85 | 86 | public CommRecyclerViewHolder setOnLongClickListener(int viewId, 87 | View.OnLongClickListener listener) { 88 | View view = getView(viewId); 89 | view.setOnLongClickListener(listener); 90 | return this; 91 | } 92 | 93 | 94 | } 95 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/widget/MagicCameraLayout.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.camera.widget; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.MotionEvent; 6 | import android.widget.FrameLayout; 7 | 8 | import com.tiktokdemo.lky.tiktokdemo.R; 9 | import com.tiktokdemo.lky.tiktokdemo.record.camera.camera.CameraEngine; 10 | 11 | 12 | /** 13 | * Created by lky on 2017/4/18. 14 | * 用于对焦提示的layout 15 | */ 16 | 17 | public class MagicCameraLayout extends FrameLayout { 18 | private MagicCameraView mMagicCameraView; 19 | private CameraFocusHintView mCameraFocusHintView; 20 | 21 | public MagicCameraLayout(Context context) { 22 | this(context,null); 23 | } 24 | 25 | public MagicCameraLayout(Context context, AttributeSet attrs) { 26 | this(context, attrs,0); 27 | } 28 | 29 | public MagicCameraLayout(Context context, AttributeSet attrs, int defStyleAttr) { 30 | super(context, attrs, defStyleAttr); 31 | initView(context); 32 | } 33 | 34 | private void initView(Context context) { 35 | // mCameraFocusHintView = new CameraFocusHintView(context); 36 | // FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); 37 | // addView(mCameraFocusHintView,layoutParams); 38 | } 39 | 40 | @Override 41 | protected void onAttachedToWindow() { 42 | super.onAttachedToWindow(); 43 | mMagicCameraView = (MagicCameraView) findViewById(R.id.tidal_pat_record_camera_view); 44 | mCameraFocusHintView = (CameraFocusHintView) findViewById(R.id.tidal_pat_record_focus_view); 45 | } 46 | 47 | @Override 48 | public boolean onTouchEvent(MotionEvent event) { 49 | if(!CameraEngine.getCameraInfo().isFront){ 50 | if (event.getPointerCount() == 1 && event.getAction() == MotionEvent.ACTION_DOWN){ 51 | if(mMagicCameraView != null){ 52 | mMagicCameraView.handleFocusMetering(event); 53 | } 54 | mCameraFocusHintView.startFocus(event); 55 | } 56 | } 57 | 58 | return super.onTouchEvent(event); 59 | 60 | 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/camera/widget/MagicImageView.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.camera.widget; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | import javax.microedition.khronos.egl.EGLConfig; 6 | import javax.microedition.khronos.opengles.GL10; 7 | 8 | import android.content.Context; 9 | import android.graphics.Bitmap; 10 | import android.util.AttributeSet; 11 | import android.util.Log; 12 | 13 | import com.tiktokdemo.lky.tiktokdemo.record.camera.beautify.MagicJni; 14 | import com.tiktokdemo.lky.tiktokdemo.record.camera.filter.base.gpuimage.GPUImageFilter; 15 | import com.tiktokdemo.lky.tiktokdemo.record.camera.helper.SavePictureTask; 16 | import com.tiktokdemo.lky.tiktokdemo.record.camera.utils.OpenGlUtils; 17 | import com.tiktokdemo.lky.tiktokdemo.record.camera.widget.base.MagicBaseView; 18 | 19 | 20 | /** 21 | * Created by why8222 on 2016/2/25. 22 | */ 23 | public class MagicImageView extends MagicBaseView { 24 | 25 | private final GPUImageFilter imageInput; 26 | 27 | private ByteBuffer _bitmapHandler = null; 28 | 29 | private Bitmap originBitmap = null; 30 | 31 | public MagicImageView(Context context) { 32 | this(context, null); 33 | } 34 | 35 | public MagicImageView(Context context, AttributeSet attrs) { 36 | super(context, attrs); 37 | imageInput = new GPUImageFilter(); 38 | } 39 | 40 | @Override 41 | public void onSurfaceCreated(GL10 gl, EGLConfig config) { 42 | super.onSurfaceCreated(gl, config); 43 | imageInput.init(); 44 | } 45 | 46 | @Override 47 | public void onSurfaceChanged(GL10 gl, int width, int height) { 48 | super.onSurfaceChanged(gl, width, height); 49 | adjustSize(0, false, false); 50 | } 51 | 52 | @Override 53 | public void onDrawFrame(GL10 gl) { 54 | super.onDrawFrame(gl); 55 | if(textureId == OpenGlUtils.NO_TEXTURE) 56 | textureId = OpenGlUtils.loadTexture(getBitmap(), OpenGlUtils.NO_TEXTURE); 57 | if(filter == null) 58 | imageInput.onDrawFrame(textureId, gLCubeBuffer, gLTextureBuffer); 59 | else 60 | filter.onDrawFrame(textureId, gLCubeBuffer, gLTextureBuffer); 61 | } 62 | 63 | @Override 64 | public void savePicture(SavePictureTask savePictureTask) { 65 | 66 | } 67 | 68 | public void setImageBitmap(Bitmap bitmap) { 69 | if (bitmap == null || bitmap.isRecycled()) 70 | return; 71 | setBitmap(bitmap); 72 | imageWidth = bitmap.getWidth(); 73 | imageHeight = bitmap.getHeight(); 74 | adjustSize(0, false, false); 75 | requestRender(); 76 | } 77 | 78 | public void initMagicBeautify(){ 79 | if(_bitmapHandler == null){ 80 | Log.e("MagicSDK", "please storeBitmap first!!"); 81 | return; 82 | } 83 | MagicJni.jniInitMagicBeautify(_bitmapHandler); 84 | } 85 | 86 | public void setBitmap(Bitmap bitmap){ 87 | if(_bitmapHandler != null) 88 | freeBitmap(); 89 | _bitmapHandler = MagicJni.jniStoreBitmapData(bitmap); 90 | originBitmap = bitmap; 91 | } 92 | 93 | public void freeBitmap(){ 94 | if(_bitmapHandler == null) 95 | return; 96 | MagicJni.jniFreeBitmapData(_bitmapHandler); 97 | _bitmapHandler = null; 98 | } 99 | 100 | public Bitmap getBitmap(){ 101 | if(_bitmapHandler == null) 102 | return null; 103 | return MagicJni.jniGetBitmapFromStoredBitmapData(_bitmapHandler); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/effects/TidalPatSpecoalEffectsManager.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.effects; 2 | 3 | /** 4 | * Created by lky on 2017/6/23. 5 | */ 6 | 7 | public class TidalPatSpecoalEffectsManager { 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/effects/adapter/TidalPatSpecialEffectsFilterClickListener.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.effects.adapter; 2 | 3 | 4 | import com.tiktokdemo.lky.tiktokdemo.record.bean.SpecialEffectsType; 5 | /** 6 | * Created by lky on 2017/6/26. 7 | */ 8 | 9 | public interface TidalPatSpecialEffectsFilterClickListener { 10 | 11 | void onItemTouchDown(int position, SpecialEffectsType specialEffectsType); 12 | void onItemTouchUp(int position); 13 | void onItemStateChange(int position, boolean isSelected, SpecialEffectsType specialEffectsType); 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/helper/RecordTimeType.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.helper; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Created by lky on 2017/8/1. 7 | */ 8 | 9 | public enum RecordTimeType implements Serializable { 10 | RECORD_TIME_15(15), 11 | RECORD_TIME_120(120); 12 | 13 | private int mSecond; 14 | 15 | RecordTimeType(int second) { 16 | this.mSecond = second; 17 | } 18 | 19 | public int getValue() { 20 | return mSecond; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/helper/TidalPatFilterType.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.helper; 2 | 3 | 4 | import com.tiktokdemo.lky.tiktokdemo.utils.AppUtil; 5 | import com.tiktokdemo.lky.tiktokdemo.R; 6 | /** 7 | * Created by lky on 2017/4/28. 8 | */ 9 | 10 | public enum TidalPatFilterType { 11 | //filterName,backgroundRes,filterRes 12 | original(AppUtil.getString(R.string.tidal_pat_filter_original),R.mipmap.filter_background_original,R.drawable.filter_original), //原图 13 | cf_17(AppUtil.getString(R.string.tidal_pat_filter_cf_17),R.mipmap.filter_cf_17,R.drawable.cf17_lut), //鲜艳 14 | sf_03(AppUtil.getString(R.string.tidal_pat_filter_sf_03),R.mipmap.filter_sf_03,R.drawable.sf03_lut), //柔和 15 | fm_05(AppUtil.getString(R.string.tidal_pat_filter_fm_05),R.mipmap.filter_fm_05,R.drawable.fm05_lut), //初夏 16 | fs_10(AppUtil.getString(R.string.tidal_pat_filter_fs_10),R.mipmap.filter_fs_10,R.drawable.fs10_lut), //小清新 17 | fm_10(AppUtil.getString(R.string.tidal_pat_filter_fm_10),R.mipmap.filter_fm_10,R.drawable.fm10_lut), //时光 18 | mod_09(AppUtil.getString(R.string.tidal_pat_filter_mod_09),R.mipmap.filter_mod_09,R.drawable.mod09_lut), //摩登 19 | re_03(AppUtil.getString(R.string.tidal_pat_filter_re_03),R.mipmap.filter_re_03,R.drawable.re03_lut), //复古风 20 | cf_19(AppUtil.getString(R.string.tidal_pat_filter_cf_19),R.mipmap.filter_cf_19,R.drawable.cf19_lut), //温暖 21 | ins_02(AppUtil.getString(R.string.tidal_pat_filter_ins_02),R.mipmap.filter_ins_02,R.drawable.ins02_lut), //怀旧 22 | bw_03(AppUtil.getString(R.string.tidal_pat_filter_bw_03),R.mipmap.filter_bw_03,R.drawable.bw03_lut); //黑白 23 | 24 | 25 | 26 | private String mFilterName; 27 | private int mFilterBackgroundRes; 28 | private int mFilterRes; 29 | TidalPatFilterType(String filterName, int filterBackgroundRes, int filterRes) { 30 | this.mFilterName = filterName; 31 | this.mFilterBackgroundRes = filterBackgroundRes; 32 | this.mFilterRes = filterRes; 33 | } 34 | 35 | public String getFilterName() { 36 | return mFilterName; 37 | } 38 | 39 | public int getFilterBackgroundRes() { 40 | return mFilterBackgroundRes; 41 | } 42 | 43 | public int getFilterRes() { 44 | return mFilterRes; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/helper/TidalPatPropInfo.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.helper; 2 | 3 | 4 | import com.tiktokdemo.lky.tiktokdemo.record.camera.filter.helper.FilterInfo; 5 | /** 6 | * Created by lky on 2017/5/3. 7 | */ 8 | 9 | public class TidalPatPropInfo { 10 | private int[] mRes; 11 | private FilterInfo mFilterInfo; 12 | private int mBackgroundRes; 13 | 14 | public void setRes(int[] res) { 15 | mRes = res; 16 | } 17 | 18 | public void setFilterInfo(FilterInfo filterInfo) { 19 | mFilterInfo = filterInfo; 20 | } 21 | 22 | public void setBackgroundRes(int backgroundRes) { 23 | mBackgroundRes = backgroundRes; 24 | } 25 | 26 | public int[] getRes() { 27 | return mRes; 28 | } 29 | 30 | public FilterInfo getFilterInfo() { 31 | return mFilterInfo; 32 | } 33 | 34 | public int getBackgroundRes() { 35 | return mBackgroundRes; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/helper/TidalPatPropType.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.helper; 2 | 3 | 4 | import com.tiktokdemo.lky.tiktokdemo.R; 5 | /** 6 | * Created by lky on 2017/5/3. 7 | */ 8 | 9 | public enum TidalPatPropType { 10 | DEFAULT(R.mipmap.chaopai_luzhi_wudaoju), 11 | CIGAR(R.mipmap.icon_cigar), 12 | GLASSES(R.mipmap.icon_glasses), 13 | FACECLOTH(R.mipmap.icon_towel), 14 | GROUP1(R.mipmap.icon_group2), 15 | GROUP2(R.mipmap.icon_group1); 16 | 17 | 18 | private int mBackgroundRes; 19 | TidalPatPropType(int backgroundRes) { 20 | this.mBackgroundRes = backgroundRes; 21 | } 22 | 23 | public int getBackgroundRes() { 24 | return mBackgroundRes; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/presenter/RecordVideoContract.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.presenter; 2 | 3 | /** 4 | * Created by lky on 2018/12/13 5 | */ 6 | public class RecordVideoContract { 7 | 8 | public interface View{ 9 | void showToast(String msg);//显示toast 10 | void showLoadingView(boolean isShow,int loadingTxtRes);//显示loading 11 | void canRecord(boolean isCan);//是否可以录制 12 | void checkMusicEmpty();//bgm不可用 13 | void checkMusicLength(int duration);//原BGM长度 14 | void createSpeedAudioSuccess();//创建各个速度的音频文件成功 15 | 16 | void combineVideoSuccess(String outputVideoPath);//合成视频成功 17 | void combineVideoFail(String errorMsg);//合成视频失败 18 | 19 | void startRecordSuccess(float progress);//开始录制成功 20 | 21 | void recordProgress(boolean isMinProgress,float progress);//录制状态回调 22 | void recordProgressForm120(float progress);//120秒模式 23 | void recordProgressMax();//达到了最大录制时间 24 | 25 | void resetRecordFinish();//重置录制完成 26 | void deleteRecordVideoFinish(boolean isCanSave);//删除录制内容完成 27 | 28 | void changeFlashModeFinish(String flashMode);//切换闪光灯模式完成 29 | void switchCameraFinish();//转换摄像头完成 30 | void changeBeautyOpenFinish(boolean isOpen);//切换美颜完成 31 | } 32 | 33 | public interface Presenter{ 34 | 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/presenter/VideoPlayContract.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.presenter; 2 | /** 3 | * Created by lky on 2018/12/13 4 | */ 5 | public class VideoPlayContract { 6 | 7 | public interface View{ 8 | void showToast(String msg);//显示toast 9 | void showLoadingView(boolean isShow,int loadingTxtRes);//显示loading 10 | void checkMusicEmpty();//bgm不可用 11 | void checkMusicLength(int duration);//原BGM长度 12 | void combineVideoStart();//开始合成视频 13 | void combineVideoFinish(boolean isLooping,String path);//合成视频完成 14 | void combineVideoError(String path);//合成视频失败 15 | void inTimeBackState(String path);//进入时光倒流状态 16 | void inTimeNotState(String path);//进入时光倒流的未选择状态 17 | void resetSpecialEffectsSeekBar(boolean isMax);//重置特效中的seekBar 18 | void changeSpecialEffectsModeFilterFinish(String path);//改变灵魂出窍模式成功 19 | void changeSpecialEffectsModeFinish(String path);//改变特效模式成功 20 | void combineDidTimeBackFinish();//完成时光倒流视频合成 21 | void completeFinish();//完成 22 | } 23 | 24 | public interface Presenter{ 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/weight/CountDownTextView.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.weight; 2 | 3 | import android.animation.AnimatorSet; 4 | import android.animation.ValueAnimator; 5 | import android.content.Context; 6 | import android.content.res.TypedArray; 7 | import android.graphics.Canvas; 8 | import android.graphics.Paint; 9 | import android.util.AttributeSet; 10 | import android.view.View; 11 | import android.view.animation.AccelerateInterpolator; 12 | import android.view.animation.BounceInterpolator; 13 | 14 | import com.tiktokdemo.lky.tiktokdemo.utils.DensityUtils; 15 | import com.tiktokdemo.lky.tiktokdemo.R; 16 | 17 | 18 | /** 19 | * Created by lky on 2017/7/4. 20 | */ 21 | 22 | public class CountDownTextView extends View { 23 | 24 | private int mTextSize; 25 | private int mTextColor; 26 | private String mTextStr = ""; 27 | private long mAnimatorDuration = 1000; 28 | 29 | private float mTextSizeScale; 30 | 31 | public CountDownTextView(Context context) { 32 | this(context,null); 33 | } 34 | 35 | public CountDownTextView(Context context, AttributeSet attrs) { 36 | this(context, attrs,0); 37 | } 38 | 39 | public CountDownTextView(Context context, AttributeSet attrs, int defStyleAttr) { 40 | super(context, attrs, defStyleAttr); 41 | TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CountDownTextView,defStyleAttr,0); 42 | mTextSize = array.getDimensionPixelOffset(R.styleable.CountDownTextView_CountDownTextSize, DensityUtils 43 | .dp2px(100)); 44 | mTextColor = array.getColor(R.styleable.CountDownTextView_CountDownTextColor,0xFFFFFFFF); 45 | // mTextStr = array.getString(R.styleable.CountDownTextView_CountDownText); 46 | init(); 47 | } 48 | 49 | public void setText(String text){ 50 | mTextStr = text; 51 | 52 | AnimatorSet set = new AnimatorSet(); 53 | ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f,1f); 54 | valueAnimator.setDuration(mAnimatorDuration/2); 55 | valueAnimator.setInterpolator(new BounceInterpolator()); 56 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 57 | @Override 58 | public void onAnimationUpdate(ValueAnimator animation) { 59 | mTextSizeScale = (float) animation.getAnimatedValue(); 60 | invalidate(); 61 | } 62 | }); 63 | 64 | ValueAnimator valueAnimator2 = ValueAnimator.ofFloat(1f,0f); 65 | valueAnimator2.setDuration(mAnimatorDuration/2); 66 | valueAnimator2.setInterpolator(new AccelerateInterpolator()); 67 | valueAnimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 68 | @Override 69 | public void onAnimationUpdate(ValueAnimator animation) { 70 | mTextSizeScale = (float) animation.getAnimatedValue(); 71 | invalidate(); 72 | } 73 | }); 74 | 75 | set.playSequentially(valueAnimator,valueAnimator2); 76 | set.start(); 77 | } 78 | 79 | public void setAnimatorDuration(long animatorDuration){ 80 | mAnimatorDuration = animatorDuration; 81 | } 82 | 83 | private void init() { 84 | 85 | } 86 | 87 | @Override 88 | protected void onDraw(Canvas canvas) { 89 | super.onDraw(canvas); 90 | 91 | Paint paint = new Paint(); 92 | paint.setAntiAlias(true); 93 | paint.setColor(mTextColor); 94 | paint.setTextSize(mTextSize * mTextSizeScale); 95 | paint.setTextAlign(Paint.Align.CENTER); 96 | 97 | Paint.FontMetrics fontMetrics = paint.getFontMetrics(); 98 | float top = fontMetrics.top; 99 | float bottom = fontMetrics.bottom; 100 | 101 | int baseLineY = (int) (getHeight()/2 - top/2 - bottom/2);//文字居中 102 | 103 | canvas.drawText(mTextStr,getWidth()/2,baseLineY,paint); 104 | 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/record/weight/ProgressAnimationListener.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.record.weight; 2 | 3 | /** 4 | * Created by eralpyucel on 11/12/2016. 5 | */ 6 | 7 | public interface ProgressAnimationListener { 8 | 9 | void onValueChanged(float value); 10 | 11 | void onAnimationEnd(); 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/utils/AppUtil.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.utils; 2 | 3 | import android.content.Context; 4 | 5 | import com.tiktokdemo.lky.tiktokdemo.BaseApplication; 6 | /** 7 | * Created by lky on 2018/12/11 8 | */ 9 | public class AppUtil { 10 | 11 | public static Context getApplicationContext(){ 12 | return BaseApplication.mContext; 13 | } 14 | 15 | public static String getString(int strRes){ 16 | return getApplicationContext().getString(strRes); 17 | } 18 | 19 | public static int getColor(int colorRes){ 20 | return getApplicationContext().getResources().getColor(colorRes); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/utils/BitmapUtil.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.utils; 2 | 3 | import java.io.File; 4 | 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.media.MediaMetadataRetriever; 8 | import android.util.Base64; 9 | 10 | import com.tiktokdemo.lky.tiktokdemo.Constant; 11 | import com.tiktokdemo.lky.tiktokdemo.R; 12 | 13 | public class BitmapUtil { 14 | private static final String TAG = "BitmapUtil"; 15 | public static Bitmap stringtoBitmap(String string){ 16 | //将字符串转换成Bitmap类型 17 | Bitmap bitmap=null; 18 | try { 19 | byte[]bitmapArray; 20 | bitmapArray= Base64.decode(string, Base64.DEFAULT); 21 | bitmap= BitmapFactory.decodeByteArray(bitmapArray, 0, bitmapArray.length); 22 | } catch (Exception e) { 23 | e.printStackTrace(); 24 | } 25 | return bitmap; 26 | } 27 | 28 | 29 | 30 | public static String saveOverlayBitmapToLocal(){ 31 | String fileName = "overlayFile.png"; 32 | File file = new File(Constant.IMAGE_SAVE_PATH + File.separator + fileName); 33 | if(file.exists()){ 34 | return file.getAbsolutePath(); 35 | } 36 | 37 | Bitmap bitmap = BitmapFactory 38 | .decodeResource(AppUtil.getApplicationContext().getResources(), R.drawable.shuiying); 39 | if(FileUtils.saveBitmapToPNG(bitmap,fileName, Constant.IMAGE_SAVE_PATH)){ 40 | return Constant.IMAGE_SAVE_PATH + File.separator + fileName; 41 | }else{ 42 | return ""; 43 | } 44 | } 45 | 46 | public static Bitmap getVideoFrame(String videoPath, int frameNumber){ 47 | try{ 48 | MediaMetadataRetriever retriever = new MediaMetadataRetriever(); 49 | retriever.setDataSource(videoPath); 50 | return retriever.getFrameAtTime(frameNumber,MediaMetadataRetriever.OPTION_CLOSEST_SYNC); 51 | }catch (Exception e){ 52 | e.printStackTrace(); 53 | } 54 | 55 | return Bitmap.createBitmap(50,50, Bitmap.Config.ARGB_8888); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/utils/CacheUtil.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.utils; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | 6 | /** 7 | * Created by 李凯源 on 2016/4/12. 8 | * 缓存类, 所有的数据都是采用SharedPreferences方式存储和获取 9 | */ 10 | public class CacheUtil { 11 | private static final String CACHE_FILE_NAME = "LkyDemo"; 12 | private static SharedPreferences mSharedPreferences; 13 | 14 | 15 | /** 16 | * @param context 17 | * @param key 18 | * 要取的数据的键 19 | * @param defValue 20 | * 缺省值 21 | * @return 22 | */ 23 | public static boolean getBoolean(Context context, String key, 24 | boolean defValue) { 25 | if (mSharedPreferences == null) { 26 | mSharedPreferences = context.getSharedPreferences(CACHE_FILE_NAME, 27 | Context.MODE_PRIVATE); 28 | } 29 | return mSharedPreferences.getBoolean(key, defValue); 30 | } 31 | 32 | /** 33 | * 存储一个boolean类型数据 34 | * 35 | * @param context 36 | * @param key 37 | * @param value 38 | */ 39 | public static void putBoolean(Context context, String key, boolean value) { 40 | if (mSharedPreferences == null) { 41 | mSharedPreferences = context.getSharedPreferences(CACHE_FILE_NAME, 42 | Context.MODE_PRIVATE); 43 | } 44 | mSharedPreferences.edit().putBoolean(key, value).commit(); 45 | } 46 | 47 | /** 48 | * 存储一个String类型的数据 49 | * 50 | * @param context 51 | * @param key 52 | * @param value 53 | */ 54 | public static void putString(Context context, String key, String value) { 55 | if (mSharedPreferences == null) { 56 | mSharedPreferences = context.getSharedPreferences(CACHE_FILE_NAME, 57 | Context.MODE_PRIVATE); 58 | } 59 | mSharedPreferences.edit().putString(key, value).commit(); 60 | } 61 | 62 | /** 63 | * 根据key取出一个String类型的值 64 | * 65 | * @param context 66 | * @param key 67 | * @param defValue 68 | * @return 69 | */ 70 | public static String getString(Context context, String key, String defValue) { 71 | if (mSharedPreferences == null) { 72 | mSharedPreferences = context.getSharedPreferences(CACHE_FILE_NAME, 73 | Context.MODE_PRIVATE); 74 | } 75 | return mSharedPreferences.getString(key, defValue); 76 | } 77 | 78 | /** 79 | * 存储一个String类型的数据 80 | * 81 | * @param context 82 | * @param key 83 | * @param value 84 | */ 85 | public static void putInt(Context context, String key, int value) { 86 | if (mSharedPreferences == null) { 87 | mSharedPreferences = context.getSharedPreferences(CACHE_FILE_NAME, 88 | Context.MODE_PRIVATE); 89 | } 90 | mSharedPreferences.edit().putInt(key, value).commit(); 91 | } 92 | 93 | /** 94 | * 根据key取出一个int类型的值 95 | * 96 | * @param context 97 | * @param key 98 | * @param defValue 99 | * @return 100 | */ 101 | public static int getInt(Context context, String key, int defValue) { 102 | if (mSharedPreferences == null) { 103 | mSharedPreferences = context.getSharedPreferences(CACHE_FILE_NAME, 104 | Context.MODE_PRIVATE); 105 | } 106 | return mSharedPreferences.getInt(key, defValue); 107 | } 108 | 109 | public static void clearData(Context context) { 110 | 111 | if (mSharedPreferences == null) { 112 | mSharedPreferences = context.getSharedPreferences(CACHE_FILE_NAME, 113 | Context.MODE_PRIVATE); 114 | } else { 115 | mSharedPreferences.edit().clear().commit(); 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/utils/CheckPermissionUtil.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.utils; 2 | 3 | import android.content.Context; 4 | import android.media.AudioFormat; 5 | import android.media.AudioRecord; 6 | import android.media.MediaRecorder; 7 | 8 | /** 9 | * Created by lky on 2017/5/16. 10 | */ 11 | 12 | public class CheckPermissionUtil { 13 | 14 | /** 15 | * 判断是是否有录音权限 16 | */ 17 | public static boolean isHasAudioPermission(final Context context){ 18 | int bufferSizeInBytes = 0; 19 | bufferSizeInBytes = AudioRecord.getMinBufferSize(44100, 20 | AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT); 21 | AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, 44100, 22 | AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSizeInBytes); 23 | //开始录制音频 24 | //开始录制音频 25 | try{ 26 | // 防止某些手机崩溃,例如联想 27 | audioRecord.startRecording(); 28 | }catch (IllegalStateException e){ 29 | e.printStackTrace(); 30 | // AVLogUtils.e(TAG, Log.getStackTraceString(e)); 31 | } 32 | /** 33 | * 根据开始录音判断是否有录音权限 34 | */ 35 | if (audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING 36 | && audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_STOPPED) { 37 | // AVLogUtils.e(TAG, "audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING : " + audioRecord.getRecordingState()); 38 | return false; 39 | } 40 | 41 | if (audioRecord.getRecordingState() == AudioRecord.RECORDSTATE_STOPPED) { 42 | //如果短时间内频繁检测,会造成audioRecord还未销毁完成,此时检测会返回RECORDSTATE_STOPPED状态,再去read,会读到0的size,可以更具自己的需求返回true或者false 43 | return false; 44 | } 45 | 46 | byte[] bytes = new byte[1024]; 47 | int readSize = audioRecord.read(bytes, 0, 1024); 48 | if (readSize == AudioRecord.ERROR_INVALID_OPERATION || readSize <= 0) { 49 | // AVLogUtils.e(TAG, "readSize illegal : " + readSize); 50 | return false; 51 | } 52 | audioRecord.stop(); 53 | audioRecord.release(); 54 | audioRecord = null; 55 | 56 | return true; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/com/tiktokdemo/lky/tiktokdemo/utils/DensityUtils.java: -------------------------------------------------------------------------------- 1 | package com.tiktokdemo.lky.tiktokdemo.utils; 2 | 3 | import android.content.Context; 4 | import android.util.TypedValue; 5 | 6 | import com.tiktokdemo.lky.tiktokdemo.BaseApplication; 7 | 8 | /** 9 | * 单位转换工具类 10 | */ 11 | public class DensityUtils { 12 | private DensityUtils() { 13 | throw new UnsupportedOperationException("cannot be instantiated"); 14 | } 15 | 16 | /** 17 | * dp转px 18 | * 19 | * @param context 20 | * @param dpVal 21 | * @return 22 | */ 23 | public static int dp2px(Context context, float dpVal) { 24 | return (int) TypedValue 25 | .applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, context.getResources().getDisplayMetrics()); 26 | } 27 | 28 | public static int dp2px( float dpVal) { 29 | return (int) TypedValue.applyDimension( 30 | TypedValue.COMPLEX_UNIT_DIP, dpVal, BaseApplication.mContext.getResources().getDisplayMetrics()); 31 | } 32 | 33 | /** 34 | * px转dp 35 | * 36 | * @param context 37 | * @param pxVal 38 | * @return 39 | */ 40 | public static float px2dp(Context context, float pxVal) { 41 | final float scale = context.getResources().getDisplayMetrics().density; 42 | 43 | return (pxVal / scale); 44 | } 45 | 46 | /** 47 | * sp转px 48 | * 49 | * @param context 50 | * @return 51 | */ 52 | public static int sp2px(Context context, float spVal) { 53 | return (int) TypedValue 54 | .applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal, context.getResources().getDisplayMetrics()); 55 | } 56 | 57 | // public static int sp2px(Context context, float spValue) { 58 | // final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 59 | // return (int) (spValue * fontScale + 0.5f); 60 | // } 61 | 62 | /** 63 | * px转sp 64 | * 65 | * @param pxVal 66 | * @return 67 | */ 68 | public static float px2sp(Context context, float pxVal) { 69 | return (pxVal / context.getResources().getDisplayMetrics().scaledDensity); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi/libffmpeg.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/src/main/jniLibs/armeabi/libffmpeg.so -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi/libheyhou_video.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/src/main/jniLibs/armeabi/libheyhou_video.so -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi/libhyphenate.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/src/main/jniLibs/armeabi/libhyphenate.so -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi/libopenh264.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/src/main/jniLibs/armeabi/libopenh264.so -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi/libpldroidplayer.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/src/main/jniLibs/armeabi/libpldroidplayer.so -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi/libspeex.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/src/main/jniLibs/armeabi/libspeex.so -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi/libyuv.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/src/main/jniLibs/armeabi/libyuv.so -------------------------------------------------------------------------------- /app/src/main/res/anim/anim_center_rotate.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/anim/dialog_enter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/anim/dialog_exit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/anim/rotate_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/bw03_lut.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/src/main/res/drawable-nodpi/bw03_lut.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/cf17_lut.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/src/main/res/drawable-nodpi/cf17_lut.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/cf19_lut.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/src/main/res/drawable-nodpi/cf19_lut.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/filter_original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/src/main/res/drawable-nodpi/filter_original.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/fm05_lut.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/src/main/res/drawable-nodpi/fm05_lut.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/fm10_lut.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/src/main/res/drawable-nodpi/fm10_lut.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/fs10_lut.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/src/main/res/drawable-nodpi/fs10_lut.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/ins02_lut.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/src/main/res/drawable-nodpi/ins02_lut.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/mod09_lut.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/src/main/res/drawable-nodpi/mod09_lut.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/re03_lut.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/src/main/res/drawable-nodpi/re03_lut.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/sf03_lut.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/src/main/res/drawable-nodpi/sf03_lut.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/shuiying.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/likaiyuan559/TikTokDemo/7392b63f0d2ecdbdd3a09393c334b20d1cc267d0/app/src/main/res/drawable-nodpi/shuiying.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/bg_big_rect_white.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/bg_common_pink_submit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/bg_round_half_transparency.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/bg_tidal_pat_record_time_red_cricle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/pop_dialog_style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/shape_common_rec_checked.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/shape_round_theme.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_few_transparency_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_gradual_black_bottom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_personal_show_video_speed_level.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_personal_show_video_speed_level_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_personal_show_video_speed_level_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_round_white.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_tidal_pat_filter_selected.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_tidal_pat_prop_selected.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_tidal_pat_record_gray.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_tidal_pat_record_time_count.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_tidal_pat_upload_save_btn.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_tidal_pat_upload_send_btn.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_white_stroke.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 |