├── .gitattributes ├── .gitignore ├── .idea ├── codeStyles │ └── Project.xml ├── gradle.xml ├── jarRepositories.xml ├── misc.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── ffmpegvideorange2 │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── ffmpegvideorange2 │ │ │ ├── App.kt │ │ │ ├── DisplayUtils.java │ │ │ ├── FileListActivity.kt │ │ │ ├── FileListAdapter.java │ │ │ ├── ImageViewBitmapBean.kt │ │ │ ├── MainActivity.java │ │ │ ├── PreviewFrameActivity.java │ │ │ ├── PreviewImageAdapter.java │ │ │ ├── RangeTimeLineActivity.kt │ │ │ ├── ShowFrameQueue.java │ │ │ ├── TimeLineActivity.kt │ │ │ ├── Utils.java │ │ │ ├── VideoRangeActivity.java │ │ │ ├── VideoUtils.java │ │ │ ├── VideoUtils2.java │ │ │ ├── YUVDataBean.kt │ │ │ ├── YuvQueue.java │ │ │ ├── cache │ │ │ └── DiskCackeHelper.kt │ │ │ ├── helper │ │ │ ├── IFFmpegCodecFrameHelper.kt │ │ │ └── IMediaCodecFrameHelper.kt │ │ │ └── scrollVelocity │ │ │ ├── ListVelocityHandler.java │ │ │ ├── RecyclerVelocityHandler.java │ │ │ ├── ScrollVelocityTracker.java │ │ │ ├── VelocityHandler.java │ │ │ ├── VelocityTrackListener.java │ │ │ ├── ViewVelocityHandler.java │ │ │ └── WeakRefWrapper.java │ └── res │ │ ├── drawable-v24 │ │ ├── ic_launcher_foreground.xml │ │ ├── play_ico.png │ │ └── stop_ico.png │ │ ├── drawable │ │ ├── drag_btn.png │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_file_list.xml │ │ ├── activity_main.xml │ │ ├── activity_preview_frame.xml │ │ ├── activity_range_time_line.xml │ │ ├── activity_time_line.xml │ │ ├── activity_video_range.xml │ │ ├── item_file_list_name.xml │ │ └── item_preview_img.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── example │ └── ffmpegvideorange2 │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── myplayer ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── myplayer │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── cpp │ │ ├── AVFrameQueue.cpp │ │ ├── AVFrameQueue.h │ │ ├── CMakeLists.txt │ │ ├── FAvFrameHelper.cpp │ │ ├── FAvFrameHelper.h │ │ ├── JavaCallHelper.cpp │ │ ├── JavaCallHelper.h │ │ ├── KzgAudio.cpp │ │ ├── KzgAudio.h │ │ ├── KzgFFmpeg.cpp │ │ ├── KzgFFmpeg.h │ │ ├── KzgPlayerStatus.cpp │ │ ├── KzgPlayerStatus.h │ │ ├── KzgVideo.cpp │ │ ├── KzgVideo.h │ │ ├── SafeQueue.cpp │ │ ├── SafeQueue.h │ │ ├── include │ │ │ ├── libavcodec │ │ │ │ ├── avcodec.h │ │ │ │ ├── avdct.h │ │ │ │ ├── avfft.h │ │ │ │ ├── d3d11va.h │ │ │ │ ├── dirac.h │ │ │ │ ├── dv_profile.h │ │ │ │ ├── dxva2.h │ │ │ │ ├── jni.h │ │ │ │ ├── mediacodec.h │ │ │ │ ├── qsv.h │ │ │ │ ├── vaapi.h │ │ │ │ ├── vda.h │ │ │ │ ├── vdpau.h │ │ │ │ ├── version.h │ │ │ │ ├── videotoolbox.h │ │ │ │ ├── vorbis_parser.h │ │ │ │ └── xvmc.h │ │ │ ├── libavdevice │ │ │ │ ├── avdevice.h │ │ │ │ └── version.h │ │ │ ├── libavfilter │ │ │ │ ├── avfilter.h │ │ │ │ ├── avfiltergraph.h │ │ │ │ ├── buffersink.h │ │ │ │ ├── buffersrc.h │ │ │ │ └── version.h │ │ │ ├── libavformat │ │ │ │ ├── avformat.h │ │ │ │ ├── avio.h │ │ │ │ └── version.h │ │ │ ├── libavutil │ │ │ │ ├── adler32.h │ │ │ │ ├── aes.h │ │ │ │ ├── aes_ctr.h │ │ │ │ ├── attributes.h │ │ │ │ ├── audio_fifo.h │ │ │ │ ├── avassert.h │ │ │ │ ├── avconfig.h │ │ │ │ ├── avstring.h │ │ │ │ ├── avutil.h │ │ │ │ ├── base64.h │ │ │ │ ├── blowfish.h │ │ │ │ ├── bprint.h │ │ │ │ ├── bswap.h │ │ │ │ ├── buffer.h │ │ │ │ ├── camellia.h │ │ │ │ ├── cast5.h │ │ │ │ ├── channel_layout.h │ │ │ │ ├── common.h │ │ │ │ ├── cpu.h │ │ │ │ ├── crc.h │ │ │ │ ├── des.h │ │ │ │ ├── dict.h │ │ │ │ ├── display.h │ │ │ │ ├── downmix_info.h │ │ │ │ ├── error.h │ │ │ │ ├── eval.h │ │ │ │ ├── ffversion.h │ │ │ │ ├── fifo.h │ │ │ │ ├── file.h │ │ │ │ ├── frame.h │ │ │ │ ├── hash.h │ │ │ │ ├── hmac.h │ │ │ │ ├── hwcontext.h │ │ │ │ ├── hwcontext_cuda.h │ │ │ │ ├── hwcontext_d3d11va.h │ │ │ │ ├── hwcontext_drm.h │ │ │ │ ├── hwcontext_dxva2.h │ │ │ │ ├── hwcontext_qsv.h │ │ │ │ ├── hwcontext_vaapi.h │ │ │ │ ├── hwcontext_vdpau.h │ │ │ │ ├── hwcontext_videotoolbox.h │ │ │ │ ├── imgutils.h │ │ │ │ ├── intfloat.h │ │ │ │ ├── intreadwrite.h │ │ │ │ ├── lfg.h │ │ │ │ ├── log.h │ │ │ │ ├── lzo.h │ │ │ │ ├── macros.h │ │ │ │ ├── mastering_display_metadata.h │ │ │ │ ├── mathematics.h │ │ │ │ ├── md5.h │ │ │ │ ├── mem.h │ │ │ │ ├── motion_vector.h │ │ │ │ ├── murmur3.h │ │ │ │ ├── opt.h │ │ │ │ ├── parseutils.h │ │ │ │ ├── pixdesc.h │ │ │ │ ├── pixelutils.h │ │ │ │ ├── pixfmt.h │ │ │ │ ├── random_seed.h │ │ │ │ ├── rational.h │ │ │ │ ├── rc4.h │ │ │ │ ├── replaygain.h │ │ │ │ ├── ripemd.h │ │ │ │ ├── samplefmt.h │ │ │ │ ├── sha.h │ │ │ │ ├── sha512.h │ │ │ │ ├── spherical.h │ │ │ │ ├── stereo3d.h │ │ │ │ ├── tea.h │ │ │ │ ├── threadmessage.h │ │ │ │ ├── time.h │ │ │ │ ├── timecode.h │ │ │ │ ├── timestamp.h │ │ │ │ ├── tree.h │ │ │ │ ├── twofish.h │ │ │ │ ├── version.h │ │ │ │ └── xtea.h │ │ │ ├── libpostproc │ │ │ │ ├── postprocess.h │ │ │ │ └── version.h │ │ │ ├── libswresample │ │ │ │ ├── swresample.h │ │ │ │ └── version.h │ │ │ └── libswscale │ │ │ │ ├── swscale.h │ │ │ │ └── version.h │ │ ├── log.h │ │ ├── mediametadataretriever │ │ │ ├── Errors.h │ │ │ ├── Mutex.h │ │ │ ├── ffmpeg_mediametadataretriever.c │ │ │ ├── ffmpeg_mediametadataretriever.h │ │ │ ├── ffmpeg_utils.c │ │ │ ├── ffmpeg_utils.h │ │ │ ├── mediametadataretriever.cpp │ │ │ ├── mediametadataretriever.h │ │ │ └── wseemann_media_MediaMetadataRetriever.cpp │ │ ├── native-lib.cpp │ │ └── soundtouch │ │ │ ├── SoundTouch │ │ │ ├── AAFilter.cpp │ │ │ ├── AAFilter.h │ │ │ ├── FIFOSampleBuffer.cpp │ │ │ ├── FIRFilter.cpp │ │ │ ├── FIRFilter.h │ │ │ ├── InterpolateCubic.cpp │ │ │ ├── InterpolateCubic.h │ │ │ ├── InterpolateLinear.cpp │ │ │ ├── InterpolateLinear.h │ │ │ ├── InterpolateShannon.cpp │ │ │ ├── InterpolateShannon.h │ │ │ ├── PeakFinder.cpp │ │ │ ├── PeakFinder.h │ │ │ ├── RateTransposer.cpp │ │ │ ├── RateTransposer.h │ │ │ ├── SoundTouch.cpp │ │ │ ├── TDStretch.cpp │ │ │ ├── TDStretch.h │ │ │ ├── cpu_detect.h │ │ │ ├── cpu_detect_x86.cpp │ │ │ └── sse_optimized.cpp │ │ │ └── include │ │ │ ├── BPMDetect.h │ │ │ ├── FIFOSampleBuffer.h │ │ │ ├── FIFOSamplePipe.h │ │ │ ├── Makefile.am │ │ │ ├── STTypes.h │ │ │ ├── SoundTouch.h │ │ │ └── soundtouch_config.h.in │ ├── java │ │ ├── com │ │ │ └── example │ │ │ │ └── myplayer │ │ │ │ ├── KzgPlayer.java │ │ │ │ ├── MyQueue.java │ │ │ │ ├── PacketBean.java │ │ │ │ ├── PacketQueue.java │ │ │ │ ├── TimeInfoBean.java │ │ │ │ ├── VideoRange │ │ │ │ ├── DividingView.java │ │ │ │ ├── MediaPlayerView.java │ │ │ │ ├── MyLinearLayoutManager.java │ │ │ │ ├── SpacesItemDecoration2.java │ │ │ │ ├── VideoPreViewAdapter.java │ │ │ │ ├── VideoRangeHorizontalScrollView.java │ │ │ │ ├── VideoRangeRecyclerView.java │ │ │ │ ├── VideoRangeView.java │ │ │ │ ├── VideoRangeViewBehavior.java │ │ │ │ └── VideoTrackView.java │ │ │ │ ├── bean │ │ │ │ ├── VideoBitmapBean.java │ │ │ │ └── YUVBean.java │ │ │ │ ├── mediacodec │ │ │ │ └── KzglVideoSupportUtil.java │ │ │ │ ├── mediacodecframes │ │ │ │ ├── OutputImageFormat.java │ │ │ │ └── VideoToFrames.java │ │ │ │ ├── opengl │ │ │ │ ├── KzgGLSurfaceView.java │ │ │ │ ├── KzgGlRender.java │ │ │ │ └── KzgShaderUtil.java │ │ │ │ ├── timebar │ │ │ │ ├── Course.java │ │ │ │ ├── ScaleModel.java │ │ │ │ ├── ScaleTimeBar.java │ │ │ │ ├── Scaler.java │ │ │ │ └── SizeParam.java │ │ │ │ └── utils │ │ │ │ └── Utils.java │ │ └── wseemann │ │ │ └── media │ │ │ └── FFmpegMediaMetadataRetriever.java │ ├── jniLibs │ │ └── armeabi-v7a │ │ │ ├── libavcodec.so │ │ │ ├── libavdevice.so │ │ │ ├── libavfilter.so │ │ │ ├── libavformat.so │ │ │ ├── libavutil.so │ │ │ ├── libpostproc.so │ │ │ ├── libswresample.so │ │ │ └── libswscale.so │ └── res │ │ ├── drawable │ │ ├── bright_progress.xml │ │ ├── bright_thumb.xml │ │ ├── btn_vidoe_pause.png │ │ ├── btn_vidoe_play.png │ │ └── selector_play_details.xml │ │ ├── layout │ │ ├── layout_video_range.xml │ │ ├── layout_view_pre_item.xml │ │ ├── video_track_layout.xml │ │ └── view_media_player.xml │ │ ├── raw │ │ ├── fragment_mediacodec.glsl │ │ ├── fragment_shader.glsl │ │ └── vertex_shader.glsl │ │ └── values │ │ └── colors.xml │ └── test │ └── java │ └── com │ └── example │ └── myplayer │ └── ExampleUnitTest.java ├── settings.gradle └── timeLine ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src ├── androidTest └── java │ └── com │ └── sam │ └── video │ └── ExampleInstrumentedTest.kt ├── main ├── AndroidManifest.xml ├── java │ └── com │ │ └── sam │ │ └── video │ │ ├── TimeLineApp.kt │ │ ├── timeline │ │ ├── adapter │ │ │ ├── TagAdapter.kt │ │ │ └── VideoFrameAdapter.kt │ │ ├── bean │ │ │ ├── TagLineViewData.kt │ │ │ ├── TargetBean.java │ │ │ ├── TimeLineAreaData.kt │ │ │ ├── VideoClip.kt │ │ │ └── VideoFrameData.kt │ │ ├── cache │ │ │ ├── DiskLruCache.java │ │ │ ├── DiskLrucacheExt.kt │ │ │ ├── IoUtils.java │ │ │ └── StrictLineReader.java │ │ ├── common │ │ │ ├── OutputImageFormat.java │ │ │ └── TargetBeanQueue.java │ │ ├── helper │ │ │ ├── DiskCacheAssist.kt │ │ │ ├── FrameCache.kt │ │ │ ├── IAvFrameHelper.kt │ │ │ ├── IFrameSearch.java │ │ │ ├── OnGetFrameBitmapCallback.kt │ │ │ ├── VideoAnalyze.kt │ │ │ └── VideoDecoder2.kt │ │ ├── listener │ │ │ ├── Click.java │ │ │ ├── OnFrameClickListener.kt │ │ │ ├── SelectAreaMagnetOnChangeListener.kt │ │ │ ├── TagSelectAreaMagnetOnChangeListener.kt │ │ │ └── VideoPlayerOperate.kt │ │ └── widget │ │ │ ├── ActiveFullTextTagLineView.kt │ │ │ ├── ActiveWideTextTagLineView.kt │ │ │ ├── MaxHeightRecyclerView.kt │ │ │ ├── RoundImageView.java │ │ │ ├── RoundRectMask.java │ │ │ ├── RoundTextView.java │ │ │ ├── RulerView.kt │ │ │ ├── SelectAreaView.kt │ │ │ ├── TagItemDecoration.kt │ │ │ ├── TagLineView.kt │ │ │ ├── TagPopWindow.kt │ │ │ ├── TimeChangeListener.kt │ │ │ ├── TimeLineBaseValue.kt │ │ │ ├── TransImageView.java │ │ │ ├── VideoFrameItemDecoration.kt │ │ │ ├── VideoFrameRecyclerView.kt │ │ │ ├── WideTextTagLineView.kt │ │ │ └── ZoomFrameLayout.kt │ │ └── util │ │ ├── AppExecutors.java │ │ ├── CodeCFunction.kt │ │ ├── Collections.kt │ │ ├── CommonFunction.kt │ │ ├── ContextExt.kt │ │ ├── FUtils.java │ │ ├── MediaFunction.kt │ │ ├── MediaStoreUtil.java │ │ ├── ScreenUtil.java │ │ ├── SelectAreaEventHandle.kt │ │ └── VideoUtils.kt └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable-xxhdpi │ ├── video_cover_duration_default.webp │ ├── video_cover_duration_disable.webp │ ├── video_edit_frame_pic_icon.webp │ ├── video_frame_cursor.webp │ ├── video_select_left.webp │ └── video_select_right.webp │ ├── drawable │ ├── ic_launcher_background.xml │ ├── shape_video_edit_filter_place_bg.xml │ ├── tag_select_white_border_corners.xml │ ├── video_edit__tip_circle_bg.xml │ ├── video_edit__tip_circle_bg_16dp.xml │ ├── video_edit__tip_line_bg_gradient.xml │ ├── video_item_index_bg.xml │ └── video_item_placeholder.xml │ ├── layout │ ├── activity_start.xml │ ├── item_tag_img.xml │ ├── item_tag_text.xml │ └── item_video_frame.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── attrs.xml │ ├── colors.xml │ ├── strings.xml │ ├── styles.xml │ └── video_edit_tag_color_res.xml └── test └── java └── com └── sam └── video └── ExampleUnitTest.kt /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | .idea 16 | 17 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 22 | 23 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FFmpegVideoRange2 2 | 3 | ## 此项目是android 仿照剪映一些功能,暂时只有预览条的精准快速抽帧显示,以及滑动过程中与播放逐帧显示,我观察了下,基本只有大厂的剪辑软件中会有这样的功能。 4 | ## 网上的一些开源项目中,都仅仅是非精准抽帧或者只是关键帧,有些速度很慢。 5 | 6 | ## 本项目抽帧速度已经和快手的快影差不多了,但是比剪映还是要慢一些,大家可以实际对比一下。 7 | 8 | ### demo 需要在内部存储根目录创建一个testVideo目录,将测试视频放到这里 9 | 10 | ### 开局一张效果图 11 | ![image](https://r.photo.store.qq.com/psc?/V53pYzs02rfsLh2OxXMT3ceYVs0kkY5m/ruAMsa53pVQWN7FLK88i5qoK1N7IVupmc5HnLP5pO6e036nwYkRdROZtREZhpAknqAIOvtltESQl5HleCjT.NfrR4F5CgkdUH411uS1K268!/mnull&bo=HAJ0BBwCdAQBCS4!&rf=photolist&t=5/r/_yake_qzoneimgout.png) 12 | ### 这是剪映的预览条加载显示的速度效果 13 | ![image](https://github.com/Destroyer716/tuchuang/blob/master/image/MyVideo_1_small.gif) 14 | 15 | ### 这是本项目的效果展示 16 | ![image](https://github.com/Destroyer716/tuchuang/blob/master/image/MyVideo_2.gif) 17 | 18 | ![image](https://github.com/Destroyer716/tuchuang/blob/master/image/MyVideo_3_small%20(1).gif) 19 | 20 | 21 | 22 | ### 其中预览条的UI 用的是https://github.com/meitu/VideoTimeLine 23 | 24 | ### 项目本身是自己学习音视频的demo,从基本的解码播放器开始一边学习一边写出来的,只支持h264的视频,此项目一点不能直接用于实际项目开发中 25 | ### 仅作为类似功能的参考,欢迎star 26 | 27 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | 5 | android { 6 | compileSdkVersion 28 7 | buildToolsVersion "29.0.2" 8 | defaultConfig { 9 | applicationId "com.example.ffmpegvideorange2" 10 | minSdkVersion 23 11 | targetSdkVersion 28 12 | versionCode 1 13 | versionName "1.0" 14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 15 | ndk { 16 | abiFilters "armeabi-v7a" 17 | } 18 | 19 | } 20 | buildTypes { 21 | release { 22 | minifyEnabled false 23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 24 | } 25 | debug { 26 | debuggable true 27 | buildConfigField "Boolean", "DEBUG_MODE", "true" 28 | } 29 | } 30 | compileOptions { 31 | sourceCompatibility JavaVersion.VERSION_1_8 32 | targetCompatibility JavaVersion.VERSION_1_8 33 | } 34 | kotlinOptions { 35 | jvmTarget = '1.8' 36 | } 37 | 38 | } 39 | 40 | dependencies { 41 | implementation fileTree(dir: 'libs', include: ['*.jar']) 42 | implementation 'androidx.appcompat:appcompat:1.1.0' 43 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 44 | implementation 'com.google.android.material:material:1.2.1' 45 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 46 | implementation project(path: ':timeLine') 47 | testImplementation 'junit:junit:4.12' 48 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 49 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 50 | implementation 'androidx.recyclerview:recyclerview:1.1.0' 51 | implementation project(path: ':myplayer') 52 | implementation 'com.wang.avi:library:2.1.3' 53 | } 54 | -------------------------------------------------------------------------------- /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/example/ffmpegvideorange2/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.example.ffmpegvideorange2; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | 25 | assertEquals("com.example.ffmpegvideorange2", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/ffmpegvideorange2/App.kt: -------------------------------------------------------------------------------- 1 | package com.example.ffmpegvideorange2 2 | 3 | import android.app.Application 4 | import android.content.Context 5 | import android.util.Log 6 | import com.sam.video.TimeLineApp 7 | import java.lang.reflect.Method 8 | 9 | 10 | class App : Application() { 11 | 12 | private var moduleApplication: TimeLineApp? = null 13 | 14 | override fun onCreate() { 15 | instance = this 16 | super.onCreate() 17 | } 18 | 19 | companion object { 20 | lateinit var instance: App 21 | private set 22 | 23 | } 24 | 25 | override fun attachBaseContext(base: Context?) { 26 | super.attachBaseContext(base) 27 | moduleApplication = getModuleApplicationInstance(this) 28 | try { 29 | //通过反射调用moduleApplication的attach方法 30 | val method: Method? = 31 | Application::class.java.getDeclaredMethod("attach", Context::class.java) 32 | Log.e("kzg","******************attachBaseContext") 33 | if (method != null) { 34 | method.setAccessible(true) 35 | method.invoke(moduleApplication, baseContext) 36 | Log.e("kzg","******************通过反射调用moduleApplication的attach方法") 37 | } 38 | } catch (e: Exception) { 39 | e.printStackTrace() 40 | } 41 | } 42 | 43 | //映射获取ModuleApplication 44 | private fun getModuleApplicationInstance(paramContext: Context): TimeLineApp? { 45 | try { 46 | if (moduleApplication == null) { 47 | val classLoader: ClassLoader = paramContext.getClassLoader() 48 | if (classLoader != null) { 49 | val mClass = classLoader.loadClass(TimeLineApp::class.java.getName()) 50 | if (mClass != null) moduleApplication = 51 | mClass.newInstance() as TimeLineApp 52 | } 53 | } 54 | } catch (e: Exception) { 55 | e.printStackTrace() 56 | } 57 | return moduleApplication 58 | } 59 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/ffmpegvideorange2/DisplayUtils.java: -------------------------------------------------------------------------------- 1 | package com.example.ffmpegvideorange2; 2 | 3 | import android.content.Context; 4 | 5 | /* 6 | * Copyright (c) 2020, jzj 7 | * Author: jzj 8 | * Website: www.paincker.com 9 | */ 10 | 11 | public class DisplayUtils { 12 | 13 | public static int dp2px(Context context, float dpValue) { 14 | final float scale = context.getResources().getDisplayMetrics().density; 15 | return (int) (dpValue * scale + 0.5f); 16 | } 17 | 18 | public static int px2dp(Context context, float pxValue) { 19 | final float scale = context.getResources().getDisplayMetrics().density; 20 | return (int) (pxValue / scale + 0.5f); 21 | } 22 | 23 | public static int dip2px(Context context, float dpValue) { 24 | return dp2px(context, dpValue); 25 | } 26 | 27 | public static int px2dip(Context context, float pxValue) { 28 | return px2dp(context, pxValue); 29 | } 30 | 31 | public static int getScreenWidth(Context c) { 32 | return c.getResources().getDisplayMetrics().widthPixels; 33 | } 34 | 35 | public static int getScreenHeight(Context c) { 36 | return c.getResources().getDisplayMetrics().heightPixels; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/ffmpegvideorange2/FileListActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.ffmpegvideorange2 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import android.os.Environment 6 | import android.util.Log 7 | import android.view.View 8 | import androidx.appcompat.app.AppCompatActivity 9 | import androidx.recyclerview.widget.LinearLayoutManager 10 | import androidx.recyclerview.widget.RecyclerView 11 | import java.io.File 12 | import java.util.* 13 | 14 | class FileListActivity : AppCompatActivity() { 15 | var inputPath = Environment.getExternalStorageDirectory().toString() + "/testVideo" 16 | 17 | private var recyclerView: RecyclerView? = null 18 | private var adapter: FileListAdapter? = null 19 | private var dataList: List? = null 20 | 21 | override fun onCreate(savedInstanceState: Bundle?) { 22 | super.onCreate(savedInstanceState) 23 | setContentView(R.layout.activity_file_list) 24 | 25 | recyclerView = findViewById(R.id.recycler_view) as RecyclerView? 26 | adapter = FileListAdapter(this) 27 | recyclerView?.setLayoutManager(LinearLayoutManager(this)) 28 | recyclerView?.setAdapter(adapter) 29 | 30 | dataList = getFileListData() 31 | adapter?.setData(dataList) 32 | adapter?.setOnItemClickListener(FileListAdapter.OnItemClickListener { position -> 33 | val intent = Intent( 34 | this@FileListActivity, 35 | RangeTimeLineActivity::class.java 36 | ) 37 | intent.putExtra("filePath", dataList!![position]) 38 | startActivity(intent) 39 | }) 40 | } 41 | 42 | 43 | private fun getFileListData(): List? { 44 | val file = File(inputPath) 45 | val files = file.listFiles() 46 | if (files == null) { 47 | Log.e("error", "空目录") 48 | return null 49 | } 50 | val s: MutableList = ArrayList() 51 | for (i in files.indices) { 52 | s.add(files[i].absolutePath) 53 | } 54 | return s 55 | } 56 | 57 | 58 | fun goToVideoRange(view: View?) { 59 | val intent = Intent( 60 | this@FileListActivity, 61 | PreviewFrameActivity::class.java 62 | ) 63 | startActivity(intent) 64 | } 65 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/ffmpegvideorange2/FileListAdapter.java: -------------------------------------------------------------------------------- 1 | package com.example.ffmpegvideorange2; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.TextView; 8 | 9 | import androidx.annotation.NonNull; 10 | import androidx.recyclerview.widget.RecyclerView; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | /** 16 | * Created By Ele 17 | * on 2020/6/25 18 | **/ 19 | public class FileListAdapter extends RecyclerView.Adapter{ 20 | 21 | private List dataList = new ArrayList<>(); 22 | private Context context; 23 | private OnItemClickListener onItemClickListener; 24 | 25 | public FileListAdapter(Context context) { 26 | this.context = context; 27 | } 28 | 29 | public void setData(List data){ 30 | if (data == null){ 31 | data = new ArrayList<>(); 32 | } 33 | dataList = data; 34 | notifyDataSetChanged(); 35 | } 36 | 37 | @NonNull 38 | @Override 39 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 40 | View inflate = LayoutInflater.from(context).inflate(R.layout.item_file_list_name, parent, false); 41 | return new ViewHolder(inflate); 42 | } 43 | 44 | @Override 45 | public void onBindViewHolder(@NonNull ViewHolder holder, final int position) { 46 | String name = dataList.get(position); 47 | holder.fileName.setText(name); 48 | holder.fileName.setOnClickListener(new View.OnClickListener() { 49 | @Override 50 | public void onClick(View v) { 51 | if (onItemClickListener != null){ 52 | onItemClickListener.onItemClick(position); 53 | } 54 | } 55 | }); 56 | } 57 | 58 | @Override 59 | public int getItemCount() { 60 | return dataList.size(); 61 | } 62 | 63 | class ViewHolder extends RecyclerView.ViewHolder{ 64 | 65 | TextView fileName; 66 | 67 | public ViewHolder(@NonNull View itemView) { 68 | super(itemView); 69 | fileName = itemView.findViewById(R.id.tv_file_name); 70 | } 71 | } 72 | 73 | 74 | public void setOnItemClickListener(OnItemClickListener onItemClickListener) { 75 | this.onItemClickListener = onItemClickListener; 76 | } 77 | 78 | public interface OnItemClickListener{ 79 | void onItemClick(int position); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/ffmpegvideorange2/ImageViewBitmapBean.kt: -------------------------------------------------------------------------------- 1 | package com.example.ffmpegvideorange2 2 | 3 | import android.graphics.Bitmap 4 | import android.graphics.Rect 5 | import android.graphics.YuvImage 6 | import android.media.Image 7 | import android.widget.ImageView 8 | import com.sam.video.timeline.bean.TargetBean 9 | 10 | class ImageViewBitmapBean(var mapEntry: Map.Entry? = null 11 | , var image: YuvImage? = null,var rect: Rect? = null,val time:Long) { 12 | 13 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/ffmpegvideorange2/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.ffmpegvideorange2; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | import androidx.recyclerview.widget.LinearLayoutManager; 5 | import androidx.recyclerview.widget.RecyclerView; 6 | 7 | import android.content.Intent; 8 | import android.graphics.Bitmap; 9 | import android.graphics.BitmapFactory; 10 | import android.graphics.Canvas; 11 | import android.graphics.Paint; 12 | import android.media.MediaCodecInfo; 13 | import android.media.MediaCodecList; 14 | import android.os.Bundle; 15 | import android.os.Environment; 16 | import android.util.Log; 17 | import android.view.SurfaceHolder; 18 | import android.view.SurfaceView; 19 | import android.view.View; 20 | import android.widget.ImageView; 21 | import android.widget.SeekBar; 22 | import android.widget.TextView; 23 | 24 | import java.io.File; 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | import wseemann.media.FFmpegMediaMetadataRetriever; 29 | 30 | 31 | public class MainActivity extends AppCompatActivity { 32 | 33 | 34 | 35 | @Override 36 | protected void onCreate(Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | setContentView(R.layout.activity_main); 39 | 40 | findViewById(R.id.tv_video_list).setOnClickListener(new View.OnClickListener() { 41 | @Override 42 | public void onClick(View v) { 43 | startActivity(new Intent(MainActivity.this,FileListActivity.class)); 44 | } 45 | }); 46 | 47 | 48 | findViewById(R.id.tv_meitu_time_line).setOnClickListener(new View.OnClickListener() { 49 | @Override 50 | public void onClick(View v) { 51 | startActivity(new Intent(MainActivity.this,TimeLineActivity.class)); 52 | } 53 | }); 54 | } 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/ffmpegvideorange2/PreviewImageAdapter.java: -------------------------------------------------------------------------------- 1 | package com.example.ffmpegvideorange2; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | import android.widget.TextView; 10 | 11 | import androidx.annotation.NonNull; 12 | import androidx.recyclerview.widget.RecyclerView; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | /** 18 | * Created By Ele 19 | * on 2020/6/25 20 | **/ 21 | public class PreviewImageAdapter extends RecyclerView.Adapter{ 22 | 23 | private List dataList = new ArrayList<>(); 24 | private Context context; 25 | private OnItemClickListener onItemClickListener; 26 | 27 | public PreviewImageAdapter(Context context) { 28 | this.context = context; 29 | } 30 | 31 | public void setData(List data){ 32 | if (data == null){ 33 | data = new ArrayList<>(); 34 | } 35 | dataList = data; 36 | notifyDataSetChanged(); 37 | } 38 | 39 | @NonNull 40 | @Override 41 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 42 | View inflate = LayoutInflater.from(context).inflate(R.layout.item_preview_img, parent, false); 43 | return new ViewHolder(inflate); 44 | } 45 | 46 | @Override 47 | public void onBindViewHolder(@NonNull ViewHolder holder, final int position) { 48 | Bitmap bitmap = dataList.get(position); 49 | holder.img.setImageBitmap(bitmap); 50 | } 51 | 52 | @Override 53 | public int getItemCount() { 54 | return dataList.size(); 55 | } 56 | 57 | class ViewHolder extends RecyclerView.ViewHolder{ 58 | 59 | ImageView img; 60 | 61 | public ViewHolder(@NonNull View itemView) { 62 | super(itemView); 63 | img = itemView.findViewById(R.id.iv_img); 64 | } 65 | } 66 | 67 | 68 | public void setOnItemClickListener(OnItemClickListener onItemClickListener) { 69 | this.onItemClickListener = onItemClickListener; 70 | } 71 | 72 | public interface OnItemClickListener{ 73 | void onItemClick(int position); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/ffmpegvideorange2/ShowFrameQueue.java: -------------------------------------------------------------------------------- 1 | package com.example.ffmpegvideorange2; 2 | 3 | import com.example.myplayer.PacketBean; 4 | import com.sam.video.timeline.bean.TargetBean; 5 | 6 | import java.util.concurrent.LinkedBlockingQueue; 7 | 8 | /** 9 | * Created By Ele 10 | * on 2020/6/4 11 | **/ 12 | public class ShowFrameQueue { 13 | 14 | private LinkedBlockingQueue list = new LinkedBlockingQueue(); 15 | 16 | public boolean enQueue(ImageViewBitmapBean packetBean){ 17 | if (list != null){ 18 | return list.offer(packetBean); 19 | } 20 | return false; 21 | } 22 | 23 | public ImageViewBitmapBean deQueue(){ 24 | if (list == null){ 25 | return null; 26 | } 27 | return list.poll(); 28 | } 29 | 30 | public ImageViewBitmapBean getFirst(){ 31 | if (list == null){ 32 | return null; 33 | } 34 | return list.peek(); 35 | } 36 | 37 | public int getQueueSize(){ 38 | if (list == null){ 39 | return 0; 40 | } 41 | return list.size(); 42 | } 43 | 44 | public synchronized void clear(){ 45 | 46 | if (list == null || list.isEmpty()){ 47 | return; 48 | } 49 | list.clear(); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/ffmpegvideorange2/YUVDataBean.kt: -------------------------------------------------------------------------------- 1 | package com.example.ffmpegvideorange2 2 | 3 | class YUVDataBean { 4 | var y:ByteArray? = null 5 | var u:ByteArray? = null 6 | var v:ByteArray? = null 7 | var yuv:ByteArray? = null 8 | var timeUs: Long = 0 9 | var width = 0 10 | var height = 0 11 | var practicalWidth = 0 12 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/ffmpegvideorange2/YuvQueue.java: -------------------------------------------------------------------------------- 1 | package com.example.ffmpegvideorange2; 2 | 3 | import java.util.concurrent.LinkedBlockingQueue; 4 | 5 | /** 6 | * Created By Ele 7 | * on 2020/6/4 8 | **/ 9 | public class YuvQueue { 10 | 11 | private LinkedBlockingQueue list = new LinkedBlockingQueue(); 12 | 13 | public boolean enQueue(YUVDataBean packetBean){ 14 | if (list != null){ 15 | return list.offer(packetBean); 16 | } 17 | return false; 18 | } 19 | 20 | public YUVDataBean deQueue(){ 21 | if (list == null){ 22 | return null; 23 | } 24 | return list.poll(); 25 | } 26 | 27 | public YUVDataBean getFirst(){ 28 | if (list == null){ 29 | return null; 30 | } 31 | return list.peek(); 32 | } 33 | 34 | public int getQueueSize(){ 35 | if (list == null){ 36 | return 0; 37 | } 38 | return list.size(); 39 | } 40 | 41 | public synchronized void clear(){ 42 | 43 | if (list == null || list.isEmpty()){ 44 | return; 45 | } 46 | list.clear(); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/ffmpegvideorange2/cache/DiskCackeHelper.kt: -------------------------------------------------------------------------------- 1 | package com.example.ffmpegvideorange2.cache 2 | 3 | class DiskCackeHelper { 4 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/ffmpegvideorange2/scrollVelocity/RecyclerVelocityHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.ffmpegvideorange2.scrollVelocity; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import androidx.annotation.CallSuper; 7 | import androidx.annotation.NonNull; 8 | import androidx.recyclerview.widget.RecyclerView; 9 | 10 | /* 11 | * Copyright (c) 2020, jzj 12 | * Author: jzj 13 | * Website: www.paincker.com 14 | */ 15 | 16 | /** 17 | * RecyclerView滚动速度监听 18 | */ 19 | public class RecyclerVelocityHandler extends RecyclerView.OnScrollListener implements VelocityHandler { 20 | 21 | private final ScrollVelocityTracker mTracker; 22 | 23 | public RecyclerVelocityHandler(Context context) { 24 | mTracker = new ScrollVelocityTracker(context); 25 | } 26 | 27 | @Override 28 | public void setThreshold(int upThreshold, int downThreshold) { 29 | mTracker.setThreshold(upThreshold, downThreshold); 30 | } 31 | 32 | @Override 33 | public void setVelocityTrackerListener(VelocityTrackListener listener) { 34 | mTracker.setVelocityTrackerListener(listener); 35 | } 36 | 37 | @Override 38 | public void setThresholdInDp(Context context, int upThreshold, int downThreshold) { 39 | mTracker.setThresholdInDp(context, upThreshold, downThreshold); 40 | } 41 | 42 | @CallSuper 43 | @Override 44 | public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { 45 | mTracker.onScrollBy(dx); 46 | } 47 | 48 | @CallSuper 49 | @Override 50 | public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { 51 | if (newState == RecyclerView.SCROLL_STATE_IDLE) { 52 | mTracker.reset(); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/ffmpegvideorange2/scrollVelocity/VelocityHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.ffmpegvideorange2.scrollVelocity; 2 | 3 | import android.content.Context; 4 | 5 | /* 6 | * Copyright (c) 2020, jzj 7 | * Author: jzj 8 | * Website: www.paincker.com 9 | */ 10 | 11 | public interface VelocityHandler { 12 | 13 | int DEFAULT_UP_THRESHOLD = 600; 14 | int DEFAULT_DOWN_THRESHOLD = 400; 15 | 16 | /** 17 | * 设置速度阈值。应该确保upThreshold >= downThreshold > 0 18 | * 19 | * @param upThreshold 速度增加超过此值时reach->true 20 | * @param downThreshold 速度减小小于此值时reach->false 21 | */ 22 | void setThresholdInDp(Context context, int upThreshold, int downThreshold); 23 | 24 | /** 25 | * 设置速度阈值。应该确保upThreshold >= downThreshold > 0 26 | * 27 | * @param upThreshold 速度增加超过此值时reach->true 28 | * @param downThreshold 速度减小小于此值时reach->false 29 | */ 30 | void setThreshold(int upThreshold, int downThreshold); 31 | 32 | /** 33 | * 设置速度监听器 34 | * 35 | * @param listener 36 | */ 37 | void setVelocityTrackerListener(VelocityTrackListener listener); 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/ffmpegvideorange2/scrollVelocity/VelocityTrackListener.java: -------------------------------------------------------------------------------- 1 | package com.example.ffmpegvideorange2.scrollVelocity;/* 2 | * Copyright (c) 2020, jzj 3 | * Author: jzj 4 | * Website: www.paincker.com 5 | */ 6 | 7 | /* 8 | * Copyright (c) 2020, jzj 9 | * Author: jzj 10 | * Website: www.paincker.com 11 | */ 12 | 13 | /** 14 | * 滚动速度监听器 15 | */ 16 | public interface VelocityTrackListener { 17 | 18 | VelocityTrackListener EMPTY_LISTENER = new VelocityTrackListener() { 19 | @Override 20 | public void onVelocityChanged(int velocity) { 21 | 22 | } 23 | 24 | @Override 25 | public void onScrollFast(int velocity) { 26 | 27 | } 28 | 29 | @Override 30 | public void onScrollSlow(int velocity) { 31 | 32 | } 33 | }; 34 | 35 | /** 36 | * 速度发生变化 37 | */ 38 | void onVelocityChanged(int velocity); 39 | 40 | /** 41 | * 快速滚动 42 | */ 43 | void onScrollFast(int velocity); 44 | 45 | /** 46 | * 慢速滚动或停止滚动 47 | */ 48 | void onScrollSlow(int velocity); 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/ffmpegvideorange2/scrollVelocity/WeakRefWrapper.java: -------------------------------------------------------------------------------- 1 | package com.example.ffmpegvideorange2.scrollVelocity; 2 | 3 | import java.lang.ref.WeakReference; 4 | 5 | /* 6 | * Copyright (c) 2020, jzj 7 | * Author: jzj 8 | * Website: www.paincker.com 9 | */ 10 | 11 | /** 12 | * 弱引用辅助类 13 | */ 14 | public class WeakRefWrapper { 15 | 16 | private WeakReference mRef; 17 | 18 | public T get() { 19 | return mRef != null ? mRef.get() : null; 20 | } 21 | 22 | public void set(T target) { 23 | mRef = target == null ? null : new WeakReference(target); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /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/play_ico.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Destroyer716/FFmpegVideoRange2/3308d11fe1fe3b3a620d1b7904e54e4c9237cd2b/app/src/main/res/drawable-v24/play_ico.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/stop_ico.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Destroyer716/FFmpegVideoRange2/3308d11fe1fe3b3a620d1b7904e54e4c9237cd2b/app/src/main/res/drawable-v24/stop_ico.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/drag_btn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Destroyer716/FFmpegVideoRange2/3308d11fe1fe3b3a620d1b7904e54e4c9237cd2b/app/src/main/res/drawable/drag_btn.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_file_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 21 | 22 | 23 | 35 | 36 |