├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── lodz │ │ └── android │ │ └── mmsplayerdemo │ │ ├── App.kt │ │ ├── MainActivity.kt │ │ ├── config │ │ └── Constant.kt │ │ ├── simple │ │ └── SimpleVideoActivity.kt │ │ ├── video │ │ ├── assist │ │ │ ├── VideoAdjustProgressLayout.kt │ │ │ ├── VideoBrightnessLayout.kt │ │ │ └── VideoVolumeLayout.kt │ │ ├── dialog │ │ │ └── VideoSettingDialog.kt │ │ ├── menu │ │ │ ├── SlideControlLayout.kt │ │ │ ├── VideoBottomMenuLayout.kt │ │ │ └── VideoTopMenuLayout.kt │ │ ├── status │ │ │ ├── VideoErrorLayout.kt │ │ │ ├── VideoLoadingAdapter.kt │ │ │ ├── VideoLoadingLayout.kt │ │ │ └── VideoPhoneDataLayout.kt │ │ └── view │ │ │ └── MediaView.kt │ │ └── widget │ │ ├── CommentAdapter.kt │ │ ├── CommentFragment.kt │ │ ├── InfoFragment.kt │ │ └── VideoActivity.kt │ └── res │ ├── anim │ ├── anim_bottom_in.xml │ ├── anim_bottom_out.xml │ ├── anim_center_in.xml │ ├── anim_center_out.xml │ ├── anim_fade_in.xml │ ├── anim_fade_out.xml │ ├── anim_left_in.xml │ ├── anim_left_out.xml │ ├── anim_right_in.xml │ ├── anim_right_out.xml │ ├── anim_top_in.xml │ └── anim_top_out.xml │ ├── drawable-xhdpi │ ├── ic_battery_1.png │ ├── ic_battery_10.png │ ├── ic_battery_2.png │ ├── ic_battery_3.png │ ├── ic_battery_4.png │ ├── ic_battery_5.png │ ├── ic_battery_6.png │ ├── ic_battery_7.png │ ├── ic_battery_8.png │ ├── ic_battery_9.png │ ├── ic_progress_video_loading_1.png │ ├── ic_progress_video_loading_2.png │ ├── ic_progress_video_loading_3.png │ ├── ic_seek_thumb.png │ ├── ic_video_brightness.png │ ├── ic_video_error.png │ ├── ic_video_pause.png │ ├── ic_video_pause_sel.png │ ├── ic_video_play.png │ ├── ic_video_play_sel.png │ ├── ic_video_screen.png │ ├── ic_video_screen_sel.png │ ├── ic_video_setting.png │ ├── ic_video_setting_sel.png │ └── ic_video_volume.png │ ├── drawable │ ├── bg_00000000_corners_5_stroke_008577.xml │ ├── bg_4c4c4c_corners_8.xml │ ├── bg_a0191919_corners_5.xml │ ├── bg_a04c4c4c_corners_8.xml │ ├── ic_launcher_background.xml │ ├── progress_video_loading_animation.xml │ ├── seekbar_color_style.xml │ ├── selector_bg_dialog_setting_item.xml │ ├── selector_bg_video_btn.xml │ ├── selector_text_dialog_setting_item.xml │ ├── selector_video_pause.xml │ ├── selector_video_play.xml │ ├── selector_video_screen.xml │ └── selector_video_setting.xml │ ├── layout │ ├── activity_main.xml │ ├── activity_simple_video.xml │ ├── activity_video.xml │ ├── dialog_video_setting.xml │ ├── fragment_comment.xml │ ├── fragment_info.xml │ ├── rv_item_comment.xml │ ├── rv_item_video_loading_tips.xml │ ├── view_media.xml │ ├── view_video_adjust_progress.xml │ ├── view_video_bottom_menu.xml │ ├── view_video_brightness.xml │ ├── view_video_error.xml │ ├── view_video_loading.xml │ ├── view_video_phone_data.xml │ ├── view_video_top_menu.xml │ └── view_video_volume.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 ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── img ├── 1_loading.png ├── 2_comment.png ├── 3_brightness_gesture.png ├── 4_volume_gesture.png ├── 5_progress_gesture.png └── 6_full_screen.png ├── mmsplayer ├── .gitignore ├── build.gradle ├── proguard-rules.pro ├── publish.gradle ├── readme_mmsplayer_update.md └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ ├── com │ │ └── lodz │ │ │ └── android │ │ │ └── mmsplayer │ │ │ ├── contract │ │ │ └── IVideoPlayer.java │ │ │ ├── ijk │ │ │ ├── bean │ │ │ │ ├── MediaInfoBean.java │ │ │ │ ├── TrackAudioInfoBean.java │ │ │ │ └── TrackVideoInfoBean.java │ │ │ ├── media │ │ │ │ ├── AndroidMediaController.java │ │ │ │ ├── FileMediaDataSource.java │ │ │ │ ├── IMediaController.java │ │ │ │ ├── IRenderView.java │ │ │ │ ├── IjkVideoView.java │ │ │ │ ├── InfoHudViewHolder.java │ │ │ │ ├── MeasureHelper.java │ │ │ │ ├── MediaPlayerCompat.java │ │ │ │ ├── SurfaceRenderView.java │ │ │ │ └── TextureRenderView.java │ │ │ ├── services │ │ │ │ └── MediaPlayerService.java │ │ │ ├── setting │ │ │ │ └── IjkPlayerSetting.java │ │ │ └── utils │ │ │ │ └── MediaInfoUtils.java │ │ │ └── impl │ │ │ └── MmsVideoView.java │ └── tv │ │ └── danmaku │ │ └── ijk │ │ └── media │ │ └── player │ │ ├── AbstractMediaPlayer.java │ │ ├── AndroidMediaPlayer.java │ │ ├── IMediaPlayer.java │ │ ├── ISurfaceTextureHolder.java │ │ ├── ISurfaceTextureHost.java │ │ ├── IjkLibLoader.java │ │ ├── IjkMediaCodecInfo.java │ │ ├── IjkMediaMeta.java │ │ ├── IjkMediaPlayer.java │ │ ├── IjkTimedText.java │ │ ├── MediaInfo.java │ │ ├── MediaPlayerProxy.java │ │ ├── TextureMediaPlayer.java │ │ ├── annotations │ │ ├── AccessedByNative.java │ │ └── CalledByNative.java │ │ ├── exceptions │ │ └── IjkMediaException.java │ │ ├── ffmpeg │ │ └── FFmpegApi.java │ │ ├── misc │ │ ├── AndroidMediaFormat.java │ │ ├── AndroidTrackInfo.java │ │ ├── IAndroidIO.java │ │ ├── IMediaDataSource.java │ │ ├── IMediaFormat.java │ │ ├── ITrackInfo.java │ │ ├── IjkMediaFormat.java │ │ └── IjkTrackInfo.java │ │ └── pragma │ │ ├── DebugLog.java │ │ └── Pragma.java │ ├── jniLibs │ ├── arm64-v8a │ │ ├── libijkffmpeg.so │ │ ├── libijkplayer.so │ │ └── libijksdl.so │ ├── armeabi-v7a │ │ ├── libijkffmpeg.so │ │ ├── libijkplayer.so │ │ └── libijksdl.so │ ├── armeabi │ │ ├── libijkffmpeg.so │ │ ├── libijkplayer.so │ │ └── libijksdl.so │ ├── x86 │ │ ├── libijkffmpeg.so │ │ ├── libijkplayer.so │ │ └── libijksdl.so │ └── x86_64 │ │ ├── libijkffmpeg.so │ │ ├── libijkplayer.so │ │ └── libijksdl.so │ └── res │ └── values │ └── strings.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches/build_file_checksums.ser 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | .DS_Store 9 | /build 10 | /captures 11 | .externalNativeBuild 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MMSPlayer播放器 2 | 基于 [IJK播放器](https://github.com/Bilibili/ijkplayer) 封装的播放器依赖库,核心播放控件使用IJKPlayer,我通过接口封装来解耦,方便调用和替换。 3 | 大家可以在基础播放器上自定义菜单页面等等,详细demo可以git工程查看或者直接进入 [VideoActivity.kt](https://github.com/LZ9/MMSPlayer/blob/master/app/src/main/java/com/lodz/android/mmsplayerdemo/widget/VideoActivity.kt) 查看。 4 | 5 | ## 目录 6 | - [1、添加Gradle依赖](https://github.com/LZ9/MMSPlayer#1添加gradle依赖) 7 | - [2、使用方法](https://github.com/LZ9/MMSPlayer#2使用方法) 8 | - [3、测试Demo(Kotlin编写)](https://github.com/LZ9/MMSPlayer#3测试demokotlin编写) 9 | - [扩展](https://github.com/LZ9/MMSPlayer#扩展) 10 | 11 | ## 1、添加Gradle依赖 12 | 由于jcenter删库跑路,请大家添加mavenCentral依赖,并引用最新版本(为了配合迁移,引用的域名从**cn.lodz**改为**ink.lodz**) 13 | ``` 14 | repositories { 15 | ... 16 | mavenCentral() 17 | ... 18 | } 19 | ``` 20 | ``` 21 | implementation 'ink.lodz:mmsplayer:1.1.2' 22 | ``` 23 | 24 | ## 2、使用方法 25 | 我封装了MmsVideoView控件,大家可以通过IVideoPlayer接口来获取控件对象,接口里有播放器的控制方法,可以通过调用接口方法来操作播放器逻辑。 26 | 27 | #### 1)在xml里添加播放器控件 28 | ``` 29 | 33 | 34 | 35 | ``` 36 | 37 | #### 2)在代码中获取控件对象 38 | ``` 39 | private val mVideoPlayer : IVideoPlayer by lazy { 40 | findViewById(R.id.video_view) 41 | } 42 | ``` 43 | 44 | #### 3)操作播放器方法 45 | ``` 46 | // 初始化(使用默认的播放器配置) 47 | mVideoPlayer.init() 48 | 49 | // 初始化(自定义播放器配置) 50 | val setting = IjkPlayerSetting.getDefault() 51 | setting.aspectRatioType = IRenderView.AR_ASPECT_FILL_PARENT 52 | mVideoPlayer.init(setting) 53 | 54 | // 设置监听器回调 55 | mVideoPlayer.setListener(object : MmsVideoView.Listener{ 56 | override fun onPrepared() { 57 | // 播放器就绪(播放路径解析完成) 58 | } 59 | 60 | override fun onBufferingStart() { 61 | // 开始缓冲 62 | } 63 | 64 | override fun onBufferingEnd() { 65 | // 结束缓冲 66 | } 67 | 68 | override fun onCompletion() { 69 | // 播放完成 70 | } 71 | 72 | override fun onError(errorType: Int, msg: String?) { 73 | // 播放出现异常 74 | } 75 | 76 | override fun onMediaPlayerCreated(mediaPlayer: IMediaPlayer) { 77 | // MediaPlayer创建完成 78 | } 79 | }) 80 | 81 | // 设置网络播放路径 82 | mVideoPlayer.setVideoPath(url) 83 | 84 | // 设置手机文件资源播放路径 85 | mVideoPlayer.setVideoURI(uri) 86 | 87 | // 开始播放 88 | mVideoPlayer.start() 89 | 90 | // 是否正在播放 91 | mVideoPlayer.isPlaying() 92 | 93 | // 是否暂停 94 | mVideoPlayer.isPause() 95 | 96 | // 是否播放结束 97 | mVideoPlayer.isCompleted() 98 | 99 | // 是否已经设置播放地址 100 | mVideoPlayer.isAlreadySetPath() 101 | 102 | // 暂停播放 103 | mVideoPlayer.pause() 104 | 105 | // 重新播放 106 | mVideoPlayer.resume() 107 | 108 | // 停止播放释放资源 109 | mVideoPlayer.release() 110 | 111 | // 获取缓存进度百分比 112 | mVideoPlayer.getBufferPercentage() 113 | 114 | // 获取当前播放进度 115 | mVideoPlayer.getCurrentPlayPosition() 116 | 117 | // 获取播放失败时的进度 118 | mVideoPlayer.getBreakPosition() 119 | 120 | // 获取视频总时长 121 | mVideoPlayer.getVideoDuration() 122 | 123 | // 设置播放位置 124 | mVideoPlayer.seekTo(1000) 125 | 126 | // 设置播放位置并开始播放 127 | mVideoPlayer.seekAndStart(1000) 128 | 129 | // 设置播放控制器(控制器需要实现IMediaController接口) 130 | mVideoPlayer.setMediaController(controller) 131 | 132 | // 设置宽高比 133 | //(IRenderView.AR_ASPECT_FIT_PARENT、IRenderView.AR_ASPECT_FILL_PARENT、 134 | // IRenderView.AR_ASPECT_WRAP_CONTENT、IRenderView.AR_MATCH_PARENT、 135 | // IRenderView.AR_16_9_FIT_PARENT、IRenderView.AR_4_3_FIT_PARENT) 136 | mVideoPlayer.setAspectRatio(IRenderView.AR_ASPECT_FILL_PARENT) 137 | 138 | // 获取视频信息 139 | mVideoPlayer.getMediaInfo() 140 | 141 | // 切换宽高比 142 | mVideoPlayer.toggleAspectRatio() 143 | 144 | // 获取当前渲染view名称 145 | mVideoPlayer.getRenderText(context) 146 | 147 | // 获取当前播放器名称 148 | mVideoPlayer.getPlayerText(context) 149 | ``` 150 | 151 | - init()和init(IjkPlayerSetting setting)根据需要选择一个调用即可 152 | - setVideoPath(String path)可以传入url和file,暂不支持资源id(例如R.raw.xxx) 153 | - IjkPlayerSetting里面可以对一些播放器参数进行配置,例如播放器类型(支持原生、IJK、EXO),宽高比、硬解或软解等等 154 | 155 | ## 3、测试Demo(Kotlin编写) 156 | - [SimpleVideoActivity.kt](https://github.com/LZ9/MMSPlayer/blob/master/app/src/main/java/com/lodz/android/mmsplayerdemo/simple/SimpleVideoActivity.kt) 接入最基础的播放器控件,方便大家了解基本调用方式 157 | - [VideoActivity.kt](https://github.com/LZ9/MMSPlayer/blob/master/app/src/main/java/com/lodz/android/mmsplayerdemo/widget/VideoActivity.kt) 我自定义了一些播放器菜单控件,并集成在 [MediaView.kt](https://github.com/LZ9/MMSPlayer/blob/master/app/src/main/java/com/lodz/android/mmsplayerdemo/video/view/MediaView.kt) 里面,供大家参考 158 | - 大家可以git工程下来,运行查看。 159 | 160 | 效果图: 161 | 162 |
163 | 164 | 165 |
166 |
167 | 168 |
169 |
170 | 171 |
172 |
173 | 174 |
175 |
176 | 177 |
178 | 179 | ## 扩展 180 | - [更新记录](https://github.com/LZ9/MMSPlayer/blob/master/mmsplayer/readme_mmsplayer_update.md) 181 | - [回到顶部](https://github.com/LZ9/MMSPlayer#mmsplayer播放器) 182 | 183 | ## License 184 | - [Apache Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html) 185 | 186 | Copyright 2022 Lodz 187 | 188 | Licensed under the Apache License, Version 2.0 (the "License"); 189 | you may not use this file except in compliance with the License. 190 | You may obtain a copy of the License at 191 | 192 | 193 | 194 | Unless required by applicable law or agreed to in writing, software 195 | distributed under the License is distributed on an "AS IS" BASIS, 196 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 197 | See the License for the specific language governing permissions and 198 | limitations under the License. 199 | 200 | s under the License. 201 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'org.jetbrains.kotlin.android' 4 | } 5 | 6 | android { 7 | compileSdk 34 8 | defaultConfig { 9 | applicationId "com.lodz.android.mmsplayerdemo" 10 | minSdkVersion 21 11 | targetSdkVersion 34 12 | versionCode 1 13 | versionName "1.0" 14 | multiDexEnabled = true// 启用dex分包 15 | } 16 | 17 | viewBinding { 18 | enabled = true 19 | } 20 | 21 | buildTypes { 22 | release { 23 | minifyEnabled false 24 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 25 | } 26 | } 27 | 28 | compileOptions { 29 | sourceCompatibility JavaVersion.VERSION_17 30 | targetCompatibility JavaVersion.VERSION_17 31 | } 32 | 33 | kotlinOptions { 34 | jvmTarget = JavaVersion.VERSION_17.toString() 35 | } 36 | 37 | lint { 38 | abortOnError false 39 | checkReleaseBuilds false 40 | } 41 | namespace 'com.lodz.android.mmsplayerdemo' 42 | } 43 | 44 | dependencies { 45 | implementation 'ink.lodz:pandora:2.0.8' 46 | 47 | implementation project(':mmsplayer') 48 | // implementation 'ink.lodz:mmsplayer:1.1.1' 49 | } 50 | -------------------------------------------------------------------------------- /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/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 20 | 21 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 36 | 37 | 38 | 39 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/lodz/android/mmsplayerdemo/App.kt: -------------------------------------------------------------------------------- 1 | package com.lodz.android.mmsplayerdemo 2 | 3 | import android.content.Context 4 | import androidx.multidex.MultiDex 5 | import com.lodz.android.corekt.network.NetworkManager 6 | import com.lodz.android.pandora.base.application.BaseApplication 7 | 8 | /** 9 | * Application 10 | * Created by zhouL on 2018/10/22. 11 | */ 12 | class App :BaseApplication(){ 13 | companion object { 14 | private var sInstance: App? = null 15 | fun get() = sInstance 16 | } 17 | 18 | override fun attachBaseContext(base: Context?) { 19 | super.attachBaseContext(base) 20 | MultiDex.install(this) 21 | } 22 | 23 | override fun onStartCreate() { 24 | sInstance = this 25 | NetworkManager.get().init(this) 26 | } 27 | 28 | override fun onExit() { 29 | } 30 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lodz/android/mmsplayerdemo/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.lodz.android.mmsplayerdemo 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import androidx.activity.result.contract.ActivityResultContracts 6 | import com.lodz.android.corekt.anko.getColorCompat 7 | import com.lodz.android.corekt.anko.toastShort 8 | import com.lodz.android.mmsplayerdemo.databinding.ActivityMainBinding 9 | import com.lodz.android.mmsplayerdemo.simple.SimpleVideoActivity 10 | import com.lodz.android.mmsplayerdemo.widget.VideoActivity 11 | import com.lodz.android.pandora.base.activity.BaseActivity 12 | import com.lodz.android.pandora.utils.viewbinding.bindingLayout 13 | 14 | class MainActivity : BaseActivity() { 15 | 16 | private val mBinding: ActivityMainBinding by bindingLayout(ActivityMainBinding::inflate) 17 | 18 | override fun getViewBindingLayout(): View = mBinding.root 19 | 20 | override fun findViews(savedInstanceState: Bundle?) { 21 | super.findViews(savedInstanceState) 22 | getTitleBarLayout().setTitleName(R.string.app_name) 23 | getTitleBarLayout().setBackgroundColor(getColorCompat(R.color.colorPrimary)) 24 | getTitleBarLayout().needBackButton(false) 25 | } 26 | 27 | override fun setListeners() { 28 | super.setListeners() 29 | mBinding.simpleBtn.setOnClickListener { 30 | mGetContentResult.launch("video/*") 31 | } 32 | 33 | mBinding.widgetBtn.setOnClickListener { 34 | VideoActivity.start(this, getString(R.string.info_name), "http://vd3.bdstatic.com/mda-nkdksvz89kgvez0j/360p/h264/1668436838593889961/mda-nkdksvz89kgvez0j.mp4") 35 | } 36 | } 37 | 38 | /** 单类型选择单文件回调 */ 39 | private val mGetContentResult = registerForActivityResult(ActivityResultContracts.GetContent()) { 40 | if (it == null){ 41 | toastShort("取消选择") 42 | return@registerForActivityResult 43 | } 44 | SimpleVideoActivity.start(this, it) 45 | } 46 | 47 | override fun initData() { 48 | super.initData() 49 | showStatusCompleted() 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/lodz/android/mmsplayerdemo/config/Constant.kt: -------------------------------------------------------------------------------- 1 | package com.lodz.android.mmsplayerdemo.config 2 | 3 | import androidx.annotation.IntDef 4 | import androidx.annotation.StringDef 5 | 6 | /** 7 | * 常量 8 | * Created by zhouL on 2018/10/31. 9 | */ 10 | object Constant { 11 | 12 | /** 不连播 */ 13 | const val UN_NEXT = 0 14 | /** 自动连播 */ 15 | const val AUTO_NEXT = 1 16 | /** 单集循环 */ 17 | const val SINGLE_CYCLE = 2 18 | /** 播完退出 */ 19 | const val EXIT_END = 3 20 | 21 | @IntDef(UN_NEXT, AUTO_NEXT, SINGLE_CYCLE, EXIT_END) 22 | @Retention(AnnotationRetention.SOURCE) 23 | annotation class PlayType 24 | 25 | 26 | /** 0.5X */ 27 | const val SPEED_0_5X = "0.5" 28 | /** 0.75X */ 29 | const val SPEED_0_75X = "0.75" 30 | /** 1.0X */ 31 | const val SPEED_1_0X = "1.0" 32 | /** 1.25X */ 33 | const val SPEED_1_25X = "1.25" 34 | /** 1.5X */ 35 | const val SPEED_1_5X = "1.5" 36 | /** 2.0X */ 37 | const val SPEED_2_0X = "2.0" 38 | 39 | @StringDef(SPEED_0_5X, SPEED_0_75X, SPEED_1_0X, SPEED_1_25X, SPEED_1_5X, SPEED_2_0X) 40 | @Retention(AnnotationRetention.SOURCE) 41 | annotation class SpeedType 42 | 43 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lodz/android/mmsplayerdemo/simple/SimpleVideoActivity.kt: -------------------------------------------------------------------------------- 1 | package com.lodz.android.mmsplayerdemo.simple 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.net.Uri 6 | import android.os.Bundle 7 | import android.view.View 8 | import com.lodz.android.corekt.anko.intentParcelableExtras 9 | import com.lodz.android.corekt.anko.toastShort 10 | import com.lodz.android.mmsplayer.contract.IVideoPlayer 11 | import com.lodz.android.mmsplayer.impl.MmsVideoView 12 | import com.lodz.android.mmsplayerdemo.R 13 | import com.lodz.android.mmsplayerdemo.databinding.ActivitySimpleVideoBinding 14 | import com.lodz.android.pandora.base.activity.AbsActivity 15 | import com.lodz.android.pandora.utils.viewbinding.bindingLayout 16 | import tv.danmaku.ijk.media.player.IMediaPlayer 17 | 18 | /** 19 | * 基础播放器界面 20 | * Created by zhouL on 2018/10/19. 21 | */ 22 | class SimpleVideoActivity : AbsActivity() { 23 | 24 | companion object { 25 | 26 | private const val EXTRA_VIDEO_PATH = "extra_video_path" 27 | 28 | fun start(context: Context, uri: Uri) { 29 | val intent = Intent(context, SimpleVideoActivity::class.java) 30 | intent.putExtra(EXTRA_VIDEO_PATH, uri) 31 | context.startActivity(intent) 32 | } 33 | } 34 | 35 | private val mBinding: ActivitySimpleVideoBinding by bindingLayout(ActivitySimpleVideoBinding::inflate) 36 | 37 | private val mUri by intentParcelableExtras(EXTRA_VIDEO_PATH) 38 | 39 | override fun getAbsViewBindingLayout(): View = mBinding.root 40 | 41 | private lateinit var mVideoPlayer: IVideoPlayer 42 | 43 | override fun findViews(savedInstanceState: Bundle?) { 44 | super.findViews(savedInstanceState) 45 | mVideoPlayer = mBinding.videoView 46 | } 47 | 48 | override fun onPressBack(): Boolean { 49 | mVideoPlayer.release() 50 | finish() 51 | return true 52 | } 53 | 54 | override fun setListeners() { 55 | super.setListeners() 56 | mVideoPlayer.setListener(object :MmsVideoView.Listener{ 57 | override fun onPrepared() { 58 | toastShort(R.string.simple_prepared) 59 | } 60 | 61 | override fun onBufferingStart() { 62 | toastShort(R.string.simple_buffering_start) 63 | } 64 | 65 | override fun onBufferingEnd() { 66 | toastShort(R.string.simple_buffering_end) 67 | } 68 | 69 | override fun onCompletion() { 70 | toastShort(R.string.simple_completion) 71 | } 72 | 73 | override fun onError(errorType: Int, msg: String?) { 74 | toastShort(getString(R.string.simple_error, msg)) 75 | } 76 | 77 | override fun onMediaPlayerCreated(mediaPlayer: IMediaPlayer) { 78 | // do something 79 | } 80 | }) 81 | } 82 | 83 | override fun initData() { 84 | super.initData() 85 | val uri = mUri 86 | if (uri == null) { 87 | toastShort("获取路径失败") 88 | finish() 89 | return 90 | } 91 | mVideoPlayer.init() 92 | mVideoPlayer.setVideoURI(uri) 93 | mVideoPlayer.start() 94 | } 95 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lodz/android/mmsplayerdemo/video/assist/VideoAdjustProgressLayout.kt: -------------------------------------------------------------------------------- 1 | package com.lodz.android.mmsplayerdemo.video.assist 2 | 3 | import android.annotation.TargetApi 4 | import android.content.Context 5 | import android.os.Build 6 | import android.util.AttributeSet 7 | import android.view.LayoutInflater 8 | import android.view.View 9 | import android.widget.LinearLayout 10 | import android.widget.TextView 11 | import androidx.viewpager.widget.ViewPager 12 | import com.lodz.android.corekt.anko.bindView 13 | import com.lodz.android.mmsplayer.ijk.utils.MediaInfoUtils 14 | import com.lodz.android.mmsplayerdemo.R 15 | 16 | /** 17 | * 进度调整页面 18 | * Created by zhouL on 2018/10/26. 19 | */ 20 | class VideoAdjustProgressLayout : LinearLayout { 21 | 22 | constructor(context: Context?) : super(context) 23 | constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) 24 | constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) 25 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 26 | constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) 27 | 28 | /** 进度 */ 29 | private val mProgressTv by bindView(R.id.progress_tv) 30 | 31 | /** 总进度 */ 32 | private var mDuration: Long = 0 33 | /** 当前进度 */ 34 | private var mCurrent: Long = 0 35 | 36 | init { 37 | LayoutInflater.from(context).inflate(R.layout.view_video_adjust_progress, this) 38 | } 39 | 40 | /** 进度调整界面是否显示 */ 41 | fun isShow(): Boolean = visibility == View.VISIBLE 42 | 43 | /** 显示进度调整界面 */ 44 | fun show() { 45 | visibility = View.VISIBLE 46 | } 47 | 48 | /** 隐藏进度调整界面 */ 49 | fun hide() { 50 | visibility = View.GONE 51 | } 52 | 53 | /** 设置总进度[duration] */ 54 | fun setDuration(duration: Long) { 55 | mDuration = duration 56 | } 57 | 58 | /** 设置当前进度[current] */ 59 | fun setCurrent(current: Long) { 60 | mCurrent = current 61 | } 62 | 63 | /** 更新进度,进度更新参数[delta] */ 64 | fun updateProgress(delta: Float) { 65 | if (mDuration <= 0) { 66 | return 67 | } 68 | mCurrent += (mDuration * delta).toLong()// 计算当前进度 69 | if (mCurrent <= 0) { 70 | mCurrent = 0 71 | } 72 | if (mCurrent >= mDuration) { 73 | mCurrent = mDuration 74 | } 75 | mProgressTv.text = context.getString(R.string.video_play_progress, MediaInfoUtils.buildTimeMilli(mCurrent), MediaInfoUtils.buildTimeMilli(mDuration)) 76 | } 77 | 78 | /** 获取当前进度 */ 79 | fun getCurrent(): Long = mCurrent 80 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lodz/android/mmsplayerdemo/video/assist/VideoBrightnessLayout.kt: -------------------------------------------------------------------------------- 1 | package com.lodz.android.mmsplayerdemo.video.assist 2 | 3 | import android.annotation.TargetApi 4 | import android.app.Activity 5 | import android.content.Context 6 | import android.os.Build 7 | import android.util.AttributeSet 8 | import android.view.LayoutInflater 9 | import android.view.View 10 | import android.view.WindowManager 11 | import android.widget.ImageView 12 | import android.widget.LinearLayout 13 | import android.widget.ProgressBar 14 | import com.lodz.android.corekt.anko.bindView 15 | import com.lodz.android.mmsplayerdemo.R 16 | 17 | /** 18 | * 亮度页面 19 | * Created by zhouL on 2018/10/29. 20 | */ 21 | class VideoBrightnessLayout : LinearLayout { 22 | 23 | /** 亮度进度条 */ 24 | private val mBrightnessProgressBar by bindView(R.id.brightness_pb) 25 | 26 | constructor(context: Context?) : super(context) 27 | constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) 28 | constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) 29 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 30 | constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) 31 | 32 | init { 33 | LayoutInflater.from(context).inflate(R.layout.view_video_brightness, this) 34 | } 35 | 36 | /** 亮度界面是否显示 */ 37 | fun isShow(): Boolean = visibility == View.VISIBLE 38 | 39 | /** 显示亮度界面 */ 40 | fun show() { 41 | visibility = View.VISIBLE 42 | } 43 | 44 | /** 隐藏亮度界面 */ 45 | fun hide() { 46 | visibility = View.GONE 47 | } 48 | 49 | /** 更新亮度,更新界面[activity],进度更新参数[delta] */ 50 | fun updateBrightness(activity: Activity, delta: Float) { 51 | val layoutParams = activity.window.attributes 52 | var current = layoutParams.screenBrightness//获取当前亮度 53 | if (current == WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE) {// 如果亮度是-1则设置默认值为0.5 54 | current = 0.5f 55 | } 56 | current += delta * WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL 57 | if (current >= WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL) { 58 | current = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL 59 | } 60 | if (current <= WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_OFF) { 61 | current = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_OFF 62 | } 63 | setBrightnessProgress(current)//设置亮度 64 | layoutParams.screenBrightness = current 65 | activity.window.attributes = layoutParams 66 | } 67 | 68 | /** 设置亮度值[brightness] */ 69 | private fun setBrightnessProgress(brightness: Float) { 70 | val progress = brightness * 100 71 | mBrightnessProgressBar.progress = progress.toInt() 72 | } 73 | 74 | 75 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lodz/android/mmsplayerdemo/video/assist/VideoVolumeLayout.kt: -------------------------------------------------------------------------------- 1 | package com.lodz.android.mmsplayerdemo.video.assist 2 | 3 | import android.annotation.TargetApi 4 | import android.app.Activity 5 | import android.content.Context 6 | import android.media.AudioManager 7 | import android.os.Build 8 | import android.util.AttributeSet 9 | import android.view.LayoutInflater 10 | import android.view.View 11 | import android.widget.ImageView 12 | import android.widget.LinearLayout 13 | import android.widget.ProgressBar 14 | import com.lodz.android.corekt.anko.bindView 15 | import com.lodz.android.mmsplayerdemo.R 16 | 17 | /** 18 | * 音量页面 19 | * Created by zhouL on 2018/10/29. 20 | */ 21 | class VideoVolumeLayout : LinearLayout { 22 | 23 | /** 音量进度条 */ 24 | private val mVolumeProgressBar by bindView(R.id.volume_pb) 25 | 26 | /** 音量管理 */ 27 | private var mAudioManager: AudioManager? = null 28 | /** 最大值 */ 29 | private var mMaxVolume = 0 30 | /** 当前音量 */ 31 | private var mCurrent = 0f 32 | 33 | constructor(context: Context?) : super(context) 34 | constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) 35 | constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) 36 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 37 | constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) 38 | 39 | init { 40 | LayoutInflater.from(context).inflate(R.layout.view_video_volume, this) 41 | } 42 | 43 | /** 音量界面是否显示 */ 44 | fun isShow(): Boolean = visibility == View.VISIBLE 45 | 46 | /** 显示音量界面 */ 47 | fun show() { 48 | visibility = View.VISIBLE 49 | } 50 | 51 | /** 隐藏音量界面 */ 52 | fun hide() { 53 | visibility = View.GONE 54 | } 55 | 56 | /** 更新音量[delta] */ 57 | fun updateVolume(activity: Activity, delta: Float) { 58 | if (mAudioManager == null) { 59 | configManager(activity) 60 | } 61 | 62 | if (mAudioManager != null) { 63 | mCurrent += delta * mMaxVolume 64 | if (mCurrent >= mMaxVolume) { 65 | mCurrent = mMaxVolume.toFloat() 66 | } 67 | if (mCurrent <= 0) { 68 | mCurrent = 0f 69 | } 70 | mVolumeProgressBar.progress = mCurrent.toInt() 71 | mAudioManager!!.setStreamVolume(AudioManager.STREAM_MUSIC, mCurrent.toInt(), 0)// 设置手机音量 72 | } 73 | } 74 | 75 | private fun configManager(activity: Activity) { 76 | mAudioManager = activity.getSystemService(Context.AUDIO_SERVICE) as AudioManager? 77 | if (mAudioManager == null) { 78 | return 79 | } 80 | mMaxVolume = mAudioManager!!.getStreamMaxVolume(AudioManager.STREAM_MUSIC)// 获取音量最大值 81 | mVolumeProgressBar.max = mMaxVolume 82 | mCurrent = mAudioManager!!.getStreamVolume(AudioManager.STREAM_MUSIC).toFloat()// 获取当前音量值 83 | } 84 | 85 | 86 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lodz/android/mmsplayerdemo/video/dialog/VideoSettingDialog.kt: -------------------------------------------------------------------------------- 1 | package com.lodz.android.mmsplayerdemo.video.dialog 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import android.content.DialogInterface 6 | import android.widget.RadioGroup 7 | import android.widget.TextView 8 | import com.lodz.android.corekt.anko.bindView 9 | import com.lodz.android.mmsplayer.ijk.media.IRenderView 10 | import com.lodz.android.mmsplayer.ijk.setting.IjkPlayerSetting 11 | import com.lodz.android.mmsplayerdemo.R 12 | import com.lodz.android.mmsplayerdemo.config.Constant 13 | import com.lodz.android.pandora.widget.dialog.BaseRightDialog 14 | 15 | /** 16 | * 播放器设置弹框 17 | * Created by zhouL on 2018/10/31. 18 | */ 19 | class VideoSettingDialog(context: Context) : BaseRightDialog(context, R.style.NoDimDialog) { 20 | 21 | /** 播放类型 */ 22 | private val mPlayTypeRg by bindView(R.id.play_type_rg) 23 | /** 宽高比 */ 24 | private val mAspectRatioRg by bindView(R.id.aspect_ratio_rg) 25 | /** 倍数 */ 26 | private val mSpeedRg by bindView(R.id.speed_rg) 27 | 28 | /** 监听器 */ 29 | private var mListener: Listener? = null 30 | 31 | /** 播放类型 */ 32 | @Constant.PlayType 33 | private var mPlayType: Int = Constant.UN_NEXT 34 | 35 | /** 倍数 */ 36 | @Constant.PlayType 37 | private var mSpeedType: String = Constant.SPEED_1_0X 38 | 39 | /** 宽高比 */ 40 | @IjkPlayerSetting.AspectRatioType 41 | private var mAspectRatioType: Int = IRenderView.AR_ASPECT_FIT_PARENT 42 | 43 | override fun getLayoutId(): Int = R.layout.dialog_video_setting 44 | 45 | override fun setListeners() { 46 | super.setListeners() 47 | mPlayTypeRg.setOnCheckedChangeListener { group, checkedId -> 48 | val playType = when (checkedId) { 49 | R.id.un_next_rb -> Constant.UN_NEXT 50 | R.id.auto_next_rb -> Constant.AUTO_NEXT 51 | R.id.single_cycle_rb -> Constant.SINGLE_CYCLE 52 | R.id.exit_end_rb -> Constant.EXIT_END 53 | else -> Constant.UN_NEXT 54 | } 55 | if (mListener != null){ 56 | mListener!!.onPlayTypeChanged(playType) 57 | } 58 | } 59 | 60 | mAspectRatioRg.setOnCheckedChangeListener { group, checkedId -> 61 | val aspectRatioType = when (checkedId) { 62 | R.id.aspect_ratio_default_rb -> IRenderView.AR_ASPECT_FIT_PARENT 63 | R.id.aspect_ratio_full_rb -> IRenderView.AR_ASPECT_FILL_PARENT 64 | R.id.aspect_ratio_16_9_rb -> IRenderView.AR_16_9_FIT_PARENT 65 | R.id.aspect_ratio_4_3_rb -> IRenderView.AR_4_3_FIT_PARENT 66 | else -> IRenderView.AR_ASPECT_FIT_PARENT 67 | } 68 | if (mListener != null){ 69 | mListener!!.onAspectRatioChanged(aspectRatioType) 70 | } 71 | } 72 | 73 | mSpeedRg.setOnCheckedChangeListener { group, checkedId -> 74 | val speedType = when (checkedId) { 75 | R.id.speed_05_rb -> Constant.SPEED_0_5X 76 | R.id.speed_075_rb -> Constant.SPEED_0_75X 77 | R.id.speed_10_rb -> Constant.SPEED_1_0X 78 | R.id.speed_125_rb -> Constant.SPEED_1_25X 79 | R.id.speed_15_rb -> Constant.SPEED_1_5X 80 | R.id.speed_20_rb -> Constant.SPEED_2_0X 81 | else -> Constant.SPEED_1_0X 82 | } 83 | if (mListener != null){ 84 | mListener!!.onSpeedTypeChanged(speedType) 85 | } 86 | } 87 | 88 | setOnCancelListener { dialog -> 89 | if (mListener != null){ 90 | mListener!!.onCancel(dialog) 91 | } 92 | } 93 | } 94 | 95 | override fun initData() { 96 | super.initData() 97 | setPlayType(mPlayType) 98 | setAspectRatio(mAspectRatioType) 99 | setSpeed(mSpeedType) 100 | } 101 | 102 | /** 初始化播放类型[playType]和宽高比[aspectRatioType] */ 103 | fun init(@Constant.PlayType playType: Int, @IjkPlayerSetting.AspectRatioType aspectRatioType: Int, @Constant.SpeedType speedType: String){ 104 | mPlayType = playType 105 | mAspectRatioType = aspectRatioType 106 | mSpeedType = speedType 107 | } 108 | 109 | /** 设置播放类型[playType] */ 110 | private fun setPlayType(@Constant.PlayType playType: Int){ 111 | when (playType) { 112 | Constant.AUTO_NEXT -> mPlayTypeRg.check(R.id.auto_next_rb) 113 | Constant.SINGLE_CYCLE -> mPlayTypeRg.check(R.id.single_cycle_rb) 114 | Constant.EXIT_END -> mPlayTypeRg.check(R.id.exit_end_rb) 115 | Constant.UN_NEXT -> mPlayTypeRg.check(R.id.un_next_rb) 116 | else -> mPlayTypeRg.check(R.id.un_next_rb) 117 | } 118 | } 119 | 120 | /** 设置宽高比[aspectRatioType] */ 121 | private fun setAspectRatio(@IjkPlayerSetting.AspectRatioType aspectRatioType: Int){ 122 | when (aspectRatioType) { 123 | IRenderView.AR_ASPECT_FILL_PARENT -> mAspectRatioRg.check(R.id.aspect_ratio_full_rb) 124 | IRenderView.AR_16_9_FIT_PARENT -> mAspectRatioRg.check(R.id.aspect_ratio_16_9_rb) 125 | IRenderView.AR_4_3_FIT_PARENT -> mAspectRatioRg.check(R.id.aspect_ratio_4_3_rb) 126 | IRenderView.AR_ASPECT_FIT_PARENT -> mAspectRatioRg.check(R.id.aspect_ratio_default_rb) 127 | else -> mAspectRatioRg.check(R.id.aspect_ratio_default_rb) 128 | } 129 | } 130 | 131 | /** 设置倍数[speedType] */ 132 | private fun setSpeed(@Constant.SpeedType speedType: String) { 133 | when (speedType) { 134 | Constant.SPEED_0_5X -> mSpeedRg.check(R.id.speed_05_rb) 135 | Constant.SPEED_0_75X -> mSpeedRg.check(R.id.speed_075_rb) 136 | Constant.SPEED_1_0X -> mSpeedRg.check(R.id.speed_10_rb) 137 | Constant.SPEED_1_25X -> mSpeedRg.check(R.id.speed_125_rb) 138 | Constant.SPEED_1_5X -> mSpeedRg.check(R.id.speed_15_rb) 139 | Constant.SPEED_2_0X -> mSpeedRg.check(R.id.speed_20_rb) 140 | else -> mSpeedRg.check(R.id.speed_10_rb) 141 | } 142 | } 143 | 144 | /** 设置监听器 */ 145 | fun setListener(listener: Listener) { 146 | mListener = listener 147 | } 148 | 149 | interface Listener { 150 | /** 播放类型改变 */ 151 | fun onPlayTypeChanged(@Constant.PlayType playType: Int) 152 | 153 | /** 宽高比改变 */ 154 | fun onAspectRatioChanged(@IjkPlayerSetting.AspectRatioType aspectRatioType: Int) 155 | 156 | /** 倍数改变 */ 157 | fun onSpeedTypeChanged(@Constant.SpeedType speedType: String) 158 | 159 | /** 取消弹框 */ 160 | fun onCancel(dialog: DialogInterface) 161 | } 162 | 163 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lodz/android/mmsplayerdemo/video/status/VideoErrorLayout.kt: -------------------------------------------------------------------------------- 1 | package com.lodz.android.mmsplayerdemo.video.status 2 | 3 | import android.annotation.TargetApi 4 | import android.content.Context 5 | import android.os.Build 6 | import android.util.AttributeSet 7 | import android.view.LayoutInflater 8 | import android.view.View 9 | import android.widget.ImageView 10 | import android.widget.LinearLayout 11 | import android.widget.TextView 12 | import com.lodz.android.corekt.anko.bindView 13 | import com.lodz.android.corekt.anko.startAnim 14 | import com.lodz.android.mmsplayerdemo.R 15 | 16 | /** 17 | * 播放失败页面 18 | * Created by zhouL on 2018/10/23. 19 | */ 20 | class VideoErrorLayout : LinearLayout { 21 | 22 | /** 返回按钮 */ 23 | private val mBackBtn by bindView(R.id.back_btn) 24 | 25 | /** 重试按钮 */ 26 | private val mRetryBtn by bindView(R.id.retry_btn) 27 | 28 | /** 返回按钮监听器 */ 29 | private var mBackListener: View.OnClickListener? = null 30 | /** 重试按钮监听器 */ 31 | private var mRetryListener: View.OnClickListener? = null 32 | 33 | constructor(context: Context?) : super(context) 34 | constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) 35 | constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) 36 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 37 | constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) 38 | 39 | init { 40 | LayoutInflater.from(context).inflate(R.layout.view_video_error, this) 41 | setListeners() 42 | } 43 | 44 | private fun setListeners() { 45 | mBackBtn.setOnClickListener { 46 | if (mBackListener != null) { 47 | mBackListener!!.onClick(it) 48 | } 49 | } 50 | 51 | mRetryBtn.setOnClickListener { 52 | if (mRetryListener != null) { 53 | mRetryListener!!.onClick(it) 54 | } 55 | } 56 | } 57 | 58 | /** 设置返回按钮监听器 */ 59 | fun setBackListener(listener: View.OnClickListener) { 60 | mBackListener = listener 61 | } 62 | 63 | /** 设置重试按钮监听器 */ 64 | fun setRetryListener(listener: View.OnClickListener) { 65 | mRetryListener = listener 66 | } 67 | 68 | /** 播放失败页是否显示 */ 69 | fun isShow(): Boolean = visibility == View.VISIBLE 70 | 71 | /** 显示播放失败页 */ 72 | fun show() { 73 | if (!isShow()) { 74 | startAnim(context, R.anim.anim_fade_in, View.VISIBLE) 75 | } 76 | } 77 | 78 | /** 隐藏播放失败页 */ 79 | fun hide() { 80 | if (isShow()) { 81 | visibility = View.GONE 82 | } 83 | } 84 | 85 | /** 设置是否全屏[isFull] */ 86 | fun setFullScreen(isFull: Boolean) { 87 | mBackBtn.visibility = if (isFull) View.VISIBLE else View.GONE 88 | } 89 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lodz/android/mmsplayerdemo/video/status/VideoLoadingAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.lodz.android.mmsplayerdemo.video.status 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 | import androidx.recyclerview.widget.RecyclerView 9 | import com.lodz.android.corekt.anko.bindView 10 | import com.lodz.android.mmsplayerdemo.R 11 | 12 | /** 13 | * 视频加载界面的文字提示适配器 14 | * Created by zhouL on 2018/10/23. 15 | */ 16 | class VideoLoadingAdapter(private val context: Context) : RecyclerView.Adapter() { 17 | 18 | private var mData: List? = null 19 | 20 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder = TipsViewHolder(getLayoutView(parent, R.layout.rv_item_video_loading_tips)) 21 | 22 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { 23 | if (holder is TipsViewHolder) { 24 | showItem(holder, position) 25 | } 26 | } 27 | 28 | private fun showItem(holder: TipsViewHolder, position: Int) { 29 | val tips = getItem(position) 30 | if (tips.isNullOrEmpty()){ 31 | return 32 | } 33 | 34 | holder.tipsTv.text = tips 35 | } 36 | 37 | fun setData(list: List) { 38 | mData = list 39 | } 40 | 41 | fun getData(): List? = mData 42 | 43 | inner class TipsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { 44 | /** 提示语 */ 45 | val tipsTv by bindView(R.id.tips_tv) 46 | } 47 | 48 | override fun getItemCount(): Int = if (mData != null) mData!!.size else 0 49 | 50 | /** 根据列表索引[position]获取数据 */ 51 | private fun getItem(position: Int): String? { 52 | if (mData == null || mData!!.size == 0) { 53 | return null 54 | } 55 | try { 56 | return mData!!.get(position) 57 | } catch (e: Exception) { 58 | e.printStackTrace() 59 | } 60 | return null 61 | } 62 | 63 | /** 在onCreateViewHolder方法中根据layoutId获取View */ 64 | private fun getLayoutView(parent: ViewGroup, layoutId: Int): View = 65 | LayoutInflater.from(context).inflate(layoutId, parent, false) 66 | 67 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lodz/android/mmsplayerdemo/video/status/VideoLoadingLayout.kt: -------------------------------------------------------------------------------- 1 | package com.lodz.android.mmsplayerdemo.video.status 2 | 3 | import android.annotation.TargetApi 4 | import android.content.Context 5 | import android.os.Build 6 | import android.util.AttributeSet 7 | import android.view.LayoutInflater 8 | import android.view.View 9 | import android.widget.ImageView 10 | import android.widget.LinearLayout 11 | import androidx.recyclerview.widget.LinearLayoutManager 12 | import androidx.recyclerview.widget.RecyclerView 13 | import com.lodz.android.corekt.anko.bindView 14 | import com.lodz.android.corekt.anko.startAnim 15 | import com.lodz.android.corekt.utils.UiHandler 16 | import com.lodz.android.mmsplayerdemo.R 17 | 18 | /** 19 | * 播放器加载页面 20 | * Created by zhouL on 2018/10/23. 21 | */ 22 | class VideoLoadingLayout : LinearLayout { 23 | 24 | /** 返回按钮 */ 25 | private val mBackBtn by bindView(R.id.back_btn) 26 | /** 数据提示列表 */ 27 | private val mRecyclerView by bindView(R.id.recycler_view) 28 | 29 | /** 提示列表适配器 */ 30 | private lateinit var mAdapter: VideoLoadingAdapter 31 | /** 提示语列表 */ 32 | private val mTipsList = ArrayList() 33 | /** 监听器 */ 34 | private var mListener: View.OnClickListener? = null 35 | 36 | constructor(context: Context?) : super(context) 37 | constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) 38 | constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) 39 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 40 | constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) 41 | 42 | init { 43 | LayoutInflater.from(context).inflate(R.layout.view_video_loading, this) 44 | initRecyclerView() 45 | setListeners() 46 | bindData(context.getString(R.string.video_loading_player_init_complete)) 47 | } 48 | 49 | private fun initRecyclerView() { 50 | val layoutManager = LinearLayoutManager(context) 51 | layoutManager.orientation = RecyclerView.VERTICAL 52 | mAdapter = VideoLoadingAdapter(context) 53 | mRecyclerView.layoutManager = layoutManager 54 | mRecyclerView.setHasFixedSize(true) 55 | mRecyclerView.adapter = mAdapter 56 | } 57 | 58 | private fun setListeners() { 59 | mBackBtn.setOnClickListener { 60 | if (mListener != null) { 61 | mListener!!.onClick(it) 62 | } 63 | } 64 | } 65 | 66 | /** 绑定数据[tips] */ 67 | private fun bindData(tips: String) { 68 | mTipsList.add(tips) 69 | mAdapter.setData(mTipsList) 70 | mAdapter.notifyDataSetChanged() 71 | mRecyclerView.smoothScrollToPosition(mTipsList.size) 72 | } 73 | 74 | /** 设置返回按钮监听器[listener] */ 75 | fun setBackListener(listener: View.OnClickListener) { 76 | mListener = listener 77 | } 78 | 79 | /** 加载页是否显示 */ 80 | fun isShow(): Boolean = visibility == View.VISIBLE 81 | 82 | /** 显示加载页 */ 83 | fun show() { 84 | if (!isShow()) { 85 | visibility = View.VISIBLE 86 | } 87 | } 88 | 89 | /** 隐藏加载页 */ 90 | fun hide() { 91 | if (isShow()) { 92 | UiHandler.postDelayed({ 93 | startAnim(context, R.anim.anim_fade_out, View.GONE) 94 | }, 300) 95 | } 96 | } 97 | 98 | /** 显示播放组件加载完成 */ 99 | fun showPlayerComplete() { 100 | bindData(context.getString(R.string.video_loading_player_view_complete)) 101 | } 102 | 103 | /** 显示加载视频地址完成 */ 104 | fun showLoadUrlComplete() { 105 | bindData(context.getString(R.string.video_loading_load_url_complete)) 106 | } 107 | 108 | /** 显示开始解析视频地址 */ 109 | fun showStartAnalysisUrl() { 110 | bindData(context.getString(R.string.video_loading_start_analysis_url)) 111 | } 112 | 113 | /** 显示解析视频地址完成 */ 114 | fun showAnalysisUrlComplete() { 115 | bindData(context.getString(R.string.video_loading_analysis_url_complete)) 116 | } 117 | 118 | /** 显示切换画质 */ 119 | fun showStartChangeQuality() { 120 | bindData(context.getString(R.string.video_loading_start_change_quality)) 121 | } 122 | 123 | /** 显示解析异常 */ 124 | fun showAnalysisError() { 125 | bindData(context.getString(R.string.video_analysis_error_tips)) 126 | } 127 | 128 | /** 显示换行 */ 129 | fun showEnter() { 130 | bindData("") 131 | } 132 | 133 | /** 设置是否全屏[isFull] */ 134 | fun setFullScreen(isFull: Boolean) { 135 | mBackBtn.visibility = if (isFull) View.VISIBLE else View.GONE 136 | } 137 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lodz/android/mmsplayerdemo/video/status/VideoPhoneDataLayout.kt: -------------------------------------------------------------------------------- 1 | package com.lodz.android.mmsplayerdemo.video.status 2 | 3 | import android.annotation.TargetApi 4 | import android.content.Context 5 | import android.os.Build 6 | import android.util.AttributeSet 7 | import android.view.LayoutInflater 8 | import android.view.View 9 | import android.view.ViewGroup 10 | import android.widget.ImageView 11 | import android.widget.LinearLayout 12 | import androidx.recyclerview.widget.RecyclerView 13 | import com.lodz.android.corekt.anko.bindView 14 | import com.lodz.android.mmsplayerdemo.R 15 | 16 | /** 17 | * 数据流量播放提示页 18 | * Created by zhouL on 2018/10/23. 19 | */ 20 | class VideoPhoneDataLayout : LinearLayout { 21 | 22 | /** 返回按钮 */ 23 | private val mBackBtn by bindView(R.id.back_btn) 24 | 25 | /** 流量播放按钮 */ 26 | private val mPlayBtn by bindView(R.id.play_btn) 27 | 28 | /** 返回按钮监听器 */ 29 | private var mBackListener: View.OnClickListener? = null 30 | /** 流量播放按钮监听器 */ 31 | private var mDataPlayListener: View.OnClickListener? = null 32 | 33 | constructor(context: Context?) : super(context) 34 | constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) 35 | constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) 36 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 37 | constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) 38 | 39 | init { 40 | LayoutInflater.from(context).inflate(R.layout.view_video_phone_data, this) 41 | setListeners() 42 | } 43 | 44 | private fun setListeners() { 45 | mBackBtn.setOnClickListener { 46 | if (mBackListener != null) { 47 | mBackListener!!.onClick(it) 48 | } 49 | } 50 | 51 | mPlayBtn.setOnClickListener { 52 | if (mDataPlayListener != null) { 53 | mDataPlayListener!!.onClick(it) 54 | } 55 | } 56 | } 57 | 58 | /** 是否需要返回按钮[isNeed] */ 59 | fun needBackBtn(isNeed: Boolean) { 60 | mBackBtn.visibility = if (isNeed) View.VISIBLE else View.GONE 61 | } 62 | 63 | /** 设置返回按钮监听器 */ 64 | fun setBackListener(listener: View.OnClickListener) { 65 | mBackListener = listener 66 | } 67 | 68 | /** 设置流量播放按钮监听器 */ 69 | fun setDataPlayListener(listener: View.OnClickListener) { 70 | mDataPlayListener = listener 71 | } 72 | 73 | /** 播放失败页是否显示 */ 74 | fun isShow(): Boolean = visibility == View.VISIBLE 75 | 76 | /** 显示播放失败页 */ 77 | fun show() { 78 | if (!isShow()) { 79 | visibility = View.VISIBLE 80 | } 81 | } 82 | 83 | /** 隐藏播放失败页 */ 84 | fun hide() { 85 | if (isShow()) { 86 | visibility = View.GONE 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lodz/android/mmsplayerdemo/widget/CommentAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.lodz.android.mmsplayerdemo.widget 2 | 3 | import android.content.Context 4 | import android.view.LayoutInflater 5 | import android.view.ViewGroup 6 | import android.widget.TextView 7 | import androidx.viewbinding.ViewBinding 8 | import com.lodz.android.mmsplayerdemo.databinding.RvItemCommentBinding 9 | import com.lodz.android.pandora.widget.rv.recycler.base.BaseVbRvAdapter 10 | import com.lodz.android.pandora.widget.rv.recycler.vh.DataVBViewHolder 11 | import java.util.* 12 | 13 | /** 14 | * 评论列表 15 | * Created by zhouL on 2018/10/29. 16 | */ 17 | class CommentAdapter(context: Context) : BaseVbRvAdapter(context) { 18 | 19 | companion object{ 20 | private val NAME_ITEM = arrayListOf("张", "陈", "王", "李", "赵", "周", "黄", "苏") 21 | private val COMMENT_ITEM = "是读千万家让逻辑单例创建旭晶无饿哦斯迪克沃尔巨坑参加过问排起物业卡卡是语文切勿偶尔软件新春快乐实际打卡罗杰斯欧文吗去我跑提出张先生快圣诞节饭" 22 | } 23 | 24 | override fun getVbInflate(): (LayoutInflater, parent: ViewGroup, attachToRoot: Boolean) -> ViewBinding = RvItemCommentBinding::inflate 25 | 26 | override fun onBind(holder: DataVBViewHolder, position: Int) { 27 | holder.getVB().apply { 28 | setName(nameTv) 29 | dateTv.text = getItem(position) ?: "" 30 | setComment(commentTv) 31 | } 32 | } 33 | 34 | private fun setName(textView: TextView) { 35 | val name = NAME_ITEM[Random().nextInt(NAME_ITEM.size)] + NAME_ITEM[Random().nextInt(NAME_ITEM.size)] + NAME_ITEM[Random().nextInt(NAME_ITEM.size)] 36 | textView.text = name 37 | } 38 | 39 | private fun setComment(textView: TextView) { 40 | val startIndex = Random().nextInt(COMMENT_ITEM.length / 2) 41 | val endIndex = Random().nextInt(COMMENT_ITEM.length / 2) + COMMENT_ITEM.length / 2 42 | textView.text = COMMENT_ITEM.substring(startIndex, endIndex) 43 | } 44 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lodz/android/mmsplayerdemo/widget/CommentFragment.kt: -------------------------------------------------------------------------------- 1 | package com.lodz.android.mmsplayerdemo.widget 2 | 3 | import android.annotation.SuppressLint 4 | import android.os.Bundle 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import androidx.recyclerview.widget.LinearLayoutManager 9 | import androidx.recyclerview.widget.RecyclerView 10 | import com.lodz.android.corekt.utils.DateUtils 11 | import com.lodz.android.mmsplayerdemo.databinding.FragmentCommentBinding 12 | import com.lodz.android.pandora.base.fragment.LazyFragment 13 | import com.lodz.android.pandora.utils.viewbinding.bindingLayout 14 | import com.lodz.android.pandora.widget.rv.anko.linear 15 | import com.lodz.android.pandora.widget.rv.anko.setup 16 | import java.util.* 17 | import kotlin.collections.ArrayList 18 | 19 | /** 20 | * 评论 21 | * Created by zhouL on 2018/10/24. 22 | */ 23 | @SuppressLint("NotifyDataSetChanged") 24 | class CommentFragment : LazyFragment() { 25 | companion object { 26 | fun newInstance(): CommentFragment = CommentFragment() 27 | } 28 | 29 | private val mBinding: FragmentCommentBinding by bindingLayout(FragmentCommentBinding::inflate) 30 | 31 | override fun getAbsViewBindingLayout(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = mBinding.root 32 | 33 | private lateinit var mAdapter: CommentAdapter 34 | 35 | override fun findViews(view: View, savedInstanceState: Bundle?) { 36 | super.findViews(view, savedInstanceState) 37 | mAdapter = mBinding.recyclerView 38 | .linear() 39 | .setup(CommentAdapter(requireContext())) 40 | mAdapter.setData(getData()) 41 | mAdapter.notifyDataSetChanged() 42 | } 43 | 44 | private fun getData(): ArrayList { 45 | val millis = System.currentTimeMillis() 46 | val list = ArrayList() 47 | for (i in 0..50) { 48 | val date = DateUtils.getFormatString(DateUtils.TYPE_2, Date(millis - i * 50000000)) 49 | list.add(date) 50 | } 51 | return list 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lodz/android/mmsplayerdemo/widget/InfoFragment.kt: -------------------------------------------------------------------------------- 1 | package com.lodz.android.mmsplayerdemo.widget 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import com.lodz.android.mmsplayerdemo.databinding.FragmentInfoBinding 8 | import com.lodz.android.pandora.base.fragment.LazyFragment 9 | import com.lodz.android.pandora.utils.viewbinding.bindingLayout 10 | 11 | /** 12 | * 简介 13 | * Created by zhouL on 2018/10/24. 14 | */ 15 | class InfoFragment : LazyFragment() { 16 | companion object { 17 | fun newInstance(): InfoFragment = InfoFragment() 18 | } 19 | 20 | private val mBinding: FragmentInfoBinding by bindingLayout(FragmentInfoBinding::inflate) 21 | 22 | override fun getAbsViewBindingLayout(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = mBinding.root 23 | } -------------------------------------------------------------------------------- /app/src/main/res/anim/anim_bottom_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/anim/anim_bottom_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/anim/anim_center_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/anim/anim_center_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/anim/anim_fade_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/anim/anim_fade_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/anim/anim_left_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/anim/anim_left_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/anim/anim_right_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/anim/anim_right_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/anim/anim_top_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/anim/anim_top_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_battery_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_battery_1.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_battery_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_battery_10.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_battery_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_battery_2.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_battery_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_battery_3.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_battery_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_battery_4.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_battery_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_battery_5.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_battery_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_battery_6.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_battery_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_battery_7.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_battery_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_battery_8.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_battery_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_battery_9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_progress_video_loading_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_progress_video_loading_1.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_progress_video_loading_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_progress_video_loading_2.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_progress_video_loading_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_progress_video_loading_3.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_seek_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_seek_thumb.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_video_brightness.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_video_brightness.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_video_error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_video_error.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_video_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_video_pause.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_video_pause_sel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_video_pause_sel.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_video_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_video_play.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_video_play_sel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_video_play_sel.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_video_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_video_screen.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_video_screen_sel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_video_screen_sel.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_video_setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_video_setting.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_video_setting_sel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_video_setting_sel.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_video_volume.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LZ9/MMSPlayer/e8d0121ba8c1ca55fdeb3442f9ad6833b85b98c3/app/src/main/res/drawable-xhdpi/ic_video_volume.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_00000000_corners_5_stroke_008577.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_4c4c4c_corners_8.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_a0191919_corners_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_a04c4c4c_corners_8.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 | 34 | 36 | 38 | 40 | 42 | 44 | 46 | 48 | 50 | 52 | 54 | 56 | 58 | 60 | 62 | 64 | 66 | 68 | 70 | 72 | 74 | 75 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/progress_video_loading_animation.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 9 | 12 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/seekbar_color_style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_bg_dialog_setting_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_bg_video_btn.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_text_dialog_setting_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_video_pause.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_video_play.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_video_screen.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_video_setting.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 |