├── .gitignore ├── README.md ├── app ├── .gitignore ├── AndroidManifest.xml ├── build.gradle ├── keystore │ └── keystore.jks ├── libs │ └── Baidu_MobAds_SDK.jar ├── proguard-rules.pro ├── res │ ├── layout │ │ ├── activity_player.xml │ │ └── activity_splash.xml │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml └── src │ └── com │ └── ishow │ └── sample │ └── videoplayer │ ├── SplashActivity.java │ ├── VideoActivity.java │ ├── constant │ └── Configure.java │ └── listener │ ├── VideoBeforeListener.java │ └── VideoPauseListener.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── images └── 01.gif ├── settings.gradle └── videoplayer ├── AndroidManifest.xml ├── build.gradle ├── proguard-rules.pro ├── res ├── drawable-xhdpi │ ├── ic_backward.png │ ├── ic_forward.png │ ├── ic_play_pause.png │ ├── ic_play_play.png │ ├── ic_to_fullscreen.png │ ├── ic_to_smallscreen.png │ ├── ic_video_back.png │ ├── ic_video_loading.png │ ├── ic_vidoe_play_next.png │ ├── normal_panel_bg.9.png │ └── progress_thumb.png ├── drawable │ ├── progress_bg.xml │ └── video_loading.xml ├── layout │ ├── media_controller.xml │ ├── media_controller_ad.xml │ ├── media_controller_loading.xml │ ├── media_controller_normal.xml │ └── media_controller_slide.xml ├── values-sw240dp │ └── dimen.xml ├── values-sw320dp │ └── dimen.xml ├── values-sw360dp │ └── dimen.xml ├── values-sw384dp │ └── dimen.xml ├── values-sw392dp │ └── dimen.xml ├── values-sw400dp │ └── dimen.xml ├── values-sw411dp │ └── dimen.xml ├── values-sw420dp │ └── dimen.xml ├── values-sw440dp │ └── dimen.xml ├── values-sw480dp │ └── dimen.xml ├── values-sw520dp │ └── dimen.xml ├── values-sw560dp │ └── dimen.xml ├── values-sw600dp │ └── dimen.xml ├── values-sw640dp │ └── dimen.xml ├── values-sw682dp │ └── dimen.xml ├── values-sw768dp │ └── dimen.xml ├── values-sw800dp │ └── dimen.xml ├── values-sw820dp │ └── dimen.xml └── values │ ├── font.xml │ ├── strings.xml │ └── strings_pref.xml └── src └── com └── ishow └── videoplayer ├── settings └── Settings.java ├── utils ├── ScreenOrientationUtils.java └── VideoUtils.java └── widget ├── MediaController.java └── media ├── IMediaController.java ├── IRenderView.java ├── MeasureHelper.java ├── SurfaceRenderView.java └── VideoView.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Example user template template 3 | ### Example user template 4 | 5 | # IntelliJ project files 6 | .idea 7 | *.iml 8 | out 9 | gen### Android template 10 | # Built application files 11 | *.apk 12 | *.ap_ 13 | 14 | # Files for the ART/Dalvik VM 15 | *.dex 16 | 17 | # Java class files 18 | *.class 19 | 20 | # Generated files 21 | bin/ 22 | gen/ 23 | out/ 24 | 25 | # Gradle files 26 | .gradle/ 27 | build/ 28 | 29 | # Local configuration file (sdk path, etc) 30 | local.properties 31 | 32 | # Proguard folder generated by Eclipse 33 | proguard/ 34 | 35 | # Log Files 36 | *.log 37 | 38 | # Android Studio Navigation editor temp files 39 | .navigation/ 40 | 41 | # Android Studio captures folder 42 | captures/ 43 | 44 | 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IJKplayerSample 2 | 3 | 本库是基于 Bilibili [ijkplayer](https://github.com/Bilibili/ijkplayer "ijkplayer") 封装而成,只使用的是最简单的播放功能,更加全面的功能请自行添加. 4 | 5 | 6 | ###一. 效果演示 7 | ![效果演示](https://github.com/BrightYu/IJKplayerSample/blob/master/images/01.gif) 8 | 9 | ###二. 使用方法 10 | 11 | ##### 1. 导入到工程中 12 | 方法a: 直接把整个VideoPlayer整合到工程中并引用 13 | 14 | ``` 15 | 1. 在setting.gradle 中加入 16 | ... 17 | include ':VideoPlayer' 18 | ... 19 | 20 | 2. 主App里面中添加 21 | ... 22 | // 视频播放库 23 | compile project(':VideoPlayer') 24 | ... 25 | 26 | ``` 27 | 方法b: 使用jcenter直接引用 28 | 29 | ``` 30 | ... 31 | compile 'com.yuhaiyang:videoplayer:0.0.1' 32 | ... 33 | 34 | ``` 35 | #######注:2016年7月7日 上传中审核中 36 | 37 | ##### 2. 代码使用 38 | 39 | a. xml引用 40 | ``` 41 | ... 42 | ... 43 | 44 | 45 | 49 | 50 | 55 | 56 | ... 57 | ... 58 | 59 | ``` 60 | 61 | 注意: 外面有包裹一个FrameLayout ,为了防止横竖屏切换VideoView大小的问题 62 | 63 | b. java实现 64 | 65 | ``` 66 | ... 67 | ... 68 | // init UI 69 | mMediaController = new MediaController(this); 70 | mMediaController.setCallBack(mCallBack); 71 | mMediaController.setPlayNextVisibility(View.GONE); 72 | mMediaController.setTitle("变形金刚2"); 73 | 74 | mVideoView = (VideoView) findViewById(R.id.video_view); 75 | mVideoView.setMediaController(mMediaController); 76 | // prefer mVideoPath 77 | mVideoView.setVideoPath("播放地址"); 78 | 79 | mVideoView.start(); 80 | ... 81 | ... 82 | ``` 83 | 84 | 85 | License 86 | ======= 87 | 88 | Copyright 2015 Haiyang Yu 89 | 90 | Licensed under the Apache License, Version 2.0 (the "License"); 91 | you may not use this file except in compliance with the License. 92 | You may obtain a copy of the License at 93 | 94 | http://www.apache.org/licenses/LICENSE-2.0 95 | 96 | Unless required by applicable law or agreed to in writing, software 97 | distributed under the License is distributed on an "AS IS" BASIS, 98 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 99 | See the License for the specific language governing permissions and 100 | limitations under the License. -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 18 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 42 | 46 | 47 | 48 | 54 | 55 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 74 | 75 | 76 | 79 | 80 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The yuhaiyang Android Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @author: y.haiyang@qq.com 17 | */ 18 | 19 | apply plugin: 'com.android.application' 20 | // 方法定义获取当前时间 21 | static def releaseTime() { 22 | return new Date().format("yyyyMMddHH") 23 | } 24 | 25 | android { 26 | compileSdkVersion COMPILE_SDK_VERSION as int 27 | buildToolsVersion BUILD_TOOLS_VERSION 28 | 29 | defaultConfig { 30 | applicationId RELEASE_APPLICATION_ID 31 | minSdkVersion MIN_SDK_VERSION as int 32 | targetSdkVersion TARGET_SDK_VERSION as int 33 | versionCode releaseTime() as int 34 | versionName VERSION_NAME 35 | } 36 | //签名 37 | signingConfigs { 38 | release { 39 | storeFile file(RELEASE_STOREFILE) 40 | storePassword RELEASE_STORE_PASSWORD 41 | keyAlias RELEASE_KEY_ALIAS 42 | keyPassword RELEASE_KEY_PASSWORD 43 | } 44 | } 45 | 46 | 47 | buildTypes { 48 | debug { 49 | signingConfig signingConfigs.release 50 | } 51 | release { 52 | minifyEnabled false 53 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 54 | signingConfig signingConfigs.release 55 | } 56 | } 57 | dexOptions { 58 | jumboMode true 59 | } 60 | sourceSets { 61 | main { 62 | manifest.srcFile 'AndroidManifest.xml' 63 | java.srcDirs = ['src'] 64 | resources.srcDirs = ['src'] 65 | aidl.srcDirs = ['src'] 66 | renderscript.srcDirs = ['src'] 67 | res.srcDirs = ['res'] 68 | assets.srcDirs = ['assets'] 69 | jniLibs.srcDirs = ['libs'] 70 | } 71 | // Move the tests to tests/java, tests/res, etc... 72 | // instrumentTest.setRoot('tests') 73 | // Move the build types to build-types/ 74 | // For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ... 75 | // This moves them out of them default location under src//... which would 76 | // conflict with src/ being used by the main source set. 77 | // Adding new build types or product flavors should be accompanied 78 | // by a similar customization. 79 | debug.setRoot('build-types/debug') 80 | release.setRoot('build-types/release') 81 | } 82 | 83 | lintOptions { 84 | checkReleaseBuilds false 85 | abortOnError false 86 | // if true, only report errors 87 | ignoreWarnings true 88 | } 89 | } 90 | 91 | 92 | 93 | dependencies { 94 | implementation fileTree(dir: 'libs', include: ['*.jar']) 95 | // 基础库 96 | implementation project(':videoplayer') 97 | } 98 | 99 | -------------------------------------------------------------------------------- /app/keystore/keystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-show/android-IJKplayerSample/a02ba1a4bc838ed028d97dc51a2d6b1ed7bed623/app/keystore/keystore.jks -------------------------------------------------------------------------------- /app/libs/Baidu_MobAds_SDK.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-show/android-IJKplayerSample/a02ba1a4bc838ed028d97dc51a2d6b1ed7bed623/app/libs/Baidu_MobAds_SDK.jar -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Develop\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/res/layout/activity_player.xml: -------------------------------------------------------------------------------- 1 | 18 | 22 | 23 | 24 | 28 | 29 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/res/layout/activity_splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | -------------------------------------------------------------------------------- /app/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-show/android-IJKplayerSample/a02ba1a4bc838ed028d97dc51a2d6b1ed7bed623/app/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | #3F51B5 21 | #303F9F 22 | #FF4081 23 | 24 | -------------------------------------------------------------------------------- /app/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 16dp 21 | 16dp 22 | 23 | -------------------------------------------------------------------------------- /app/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | VideoPlayerSample 20 | 21 | -------------------------------------------------------------------------------- /app/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/com/ishow/sample/videoplayer/SplashActivity.java: -------------------------------------------------------------------------------- 1 | package com.ishow.sample.videoplayer; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.util.Log; 7 | import android.widget.RelativeLayout; 8 | 9 | import com.baidu.mobads.SplashAd; 10 | import com.baidu.mobads.SplashAdListener; 11 | import com.ishow.sample.videoplayer.constant.Configure; 12 | 13 | /** 14 | * 实时开屏,广告实时请求并且立即展现 15 | */ 16 | public class SplashActivity extends Activity { 17 | private static final String TAG = "SplashActivity"; 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | 23 | if (!Configure.SHOW_BAIDU_AD) { 24 | Intent intent = new Intent(SplashActivity.this, VideoActivity.class); 25 | startActivity(intent); 26 | SplashActivity.this.finish(); 27 | finish(); 28 | return; 29 | } 30 | 31 | setContentView(R.layout.activity_splash); 32 | RelativeLayout adContent = (RelativeLayout) this.findViewById(R.id.ad); 33 | new SplashAd(this, adContent, mSplashAdListener, Configure.BAIDU_SPLASH_ID, true); 34 | } 35 | 36 | /** 37 | * 监听 38 | */ 39 | private SplashAdListener mSplashAdListener = new SplashAdListener() { 40 | @Override 41 | public void onAdDismissed() { 42 | Log.i(TAG, "onAdDismissed"); 43 | Intent intent = new Intent(SplashActivity.this, VideoActivity.class); 44 | startActivity(intent); 45 | SplashActivity.this.finish(); 46 | } 47 | 48 | @Override 49 | public void onAdFailed(String arg0) { 50 | Log.i(TAG, "onAdFailed"); 51 | Intent intent = new Intent(SplashActivity.this, VideoActivity.class); 52 | startActivity(intent); 53 | SplashActivity.this.finish(); 54 | } 55 | 56 | @Override 57 | public void onAdPresent() { 58 | Log.i(TAG, "onAdPresent"); 59 | } 60 | 61 | @Override 62 | public void onAdClick() { 63 | Log.i("SplashActivity", "onAdClick"); 64 | // 设置开屏可接受点击时,该回调可用 65 | } 66 | }; 67 | 68 | 69 | } 70 | -------------------------------------------------------------------------------- /app/src/com/ishow/sample/videoplayer/VideoActivity.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 The yuhaiyang Android Source Project 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @author: y.haiyang@qq.com 17 | */ 18 | 19 | package com.ishow.sample.videoplayer; 20 | 21 | import android.content.res.Configuration; 22 | import android.os.Bundle; 23 | import android.os.Handler; 24 | import android.support.v7.app.AppCompatActivity; 25 | import android.util.Log; 26 | import android.view.View; 27 | 28 | import com.baidu.mobads.AdSize; 29 | import com.baidu.mobads.InterstitialAd; 30 | import com.ishow.sample.videoplayer.constant.Configure; 31 | import com.ishow.sample.videoplayer.listener.VideoBeforeListener; 32 | import com.ishow.sample.videoplayer.listener.VideoPauseListener; 33 | import com.ishow.videoplayer.utils.ScreenOrientationUtils; 34 | import com.ishow.videoplayer.widget.MediaController; 35 | import com.ishow.videoplayer.widget.media.VideoView; 36 | 37 | import tv.danmaku.ijk.media.player.IjkMediaPlayer; 38 | 39 | public class VideoActivity extends AppCompatActivity { 40 | private static final String TAG = "VideoActivity"; 41 | private MediaController mMediaController; 42 | private VideoView mVideoView; 43 | private InterstitialAd mBaiduBeforeAd; 44 | private InterstitialAd mBaiduPauseAd; 45 | 46 | @Override 47 | protected void onCreate(Bundle savedInstanceState) { 48 | super.onCreate(savedInstanceState); 49 | setContentView(R.layout.activity_player); 50 | 51 | // init UI 52 | mMediaController = new MediaController(this); 53 | mMediaController.setCallBack(mCallBack); 54 | mMediaController.setPlayNextVisibility(View.GONE); 55 | mMediaController.setTitle("加勒比海盗4"); 56 | 57 | mVideoView = (VideoView) findViewById(R.id.video_view); 58 | mVideoView.setMediaController(mMediaController); 59 | // prefer mVideoPath 60 | //mVideoView.setVideoPath("http://wx.pinet.cc:8081/plife2/vieos/加勒比海盗4惊涛怪浪/playlist.m3u8"); 61 | mVideoView.setVideoPath("http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear4/prog_index.m3u8"); 62 | 63 | mVideoView.start(); 64 | createAd(); 65 | } 66 | 67 | @Override 68 | protected void onResume() { 69 | super.onResume(); 70 | 71 | if (!Configure.SHOW_BAIDU_AD) { 72 | Log.i(TAG, "onResume: Configure.SHOW_BAIDU_AD is false"); 73 | return; 74 | } 75 | 76 | mHandler.postDelayed(new Runnable() { 77 | @Override 78 | public void run() { 79 | Log.i(TAG, "run: postDelayed"); 80 | mBaiduBeforeAd.loadAdForVideoApp(mVideoView.getWidth(), mVideoView.getHeight()); 81 | mBaiduPauseAd.loadAdForVideoApp(mVideoView.getWidth(), mVideoView.getHeight()); 82 | } 83 | }, 500); 84 | } 85 | 86 | private Handler mHandler = new Handler() { 87 | }; 88 | 89 | @Override 90 | protected void onStop() { 91 | super.onStop(); 92 | if (mVideoView.canPause()) { 93 | mVideoView.pause(); 94 | } 95 | } 96 | 97 | @Override 98 | public void onBackPressed() { 99 | if (ScreenOrientationUtils.isLandscape(this)) { 100 | mMediaController.changePortrait(false); 101 | } else { 102 | super.onBackPressed(); 103 | } 104 | } 105 | 106 | @Override 107 | protected void onDestroy() { 108 | mVideoView.stopPlayback(); 109 | mVideoView.release(true); 110 | IjkMediaPlayer.native_profileEnd(); 111 | super.onDestroy(); 112 | } 113 | 114 | @Override 115 | public void onConfigurationChanged(Configuration newConfig) { 116 | super.onConfigurationChanged(newConfig); 117 | // 切换到横屏 118 | if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { 119 | mMediaController.changeLand(true); 120 | } else { 121 | mMediaController.changePortrait(true); 122 | } 123 | } 124 | 125 | 126 | private MediaController.CallBack mCallBack = new MediaController.CallBack() { 127 | @Override 128 | public void onPlay(boolean isPlaying) { 129 | if (!isPlaying && Configure.SHOW_BAIDU_AD) { 130 | mBaiduPauseAd.showAdInParentForVideoApp(VideoActivity.this, mMediaController.getAdView()); 131 | } 132 | } 133 | 134 | @Override 135 | public void onComplete() { 136 | 137 | } 138 | 139 | @Override 140 | public void onPlayNext() { 141 | 142 | } 143 | }; 144 | 145 | private void createAd() { 146 | if (!Configure.SHOW_BAIDU_AD) { 147 | Log.i(TAG, "createAd: Configure.SHOW_BAIDU_AD is false"); 148 | return; 149 | } 150 | mBaiduBeforeAd = new InterstitialAd(this, AdSize.InterstitialForVideoBeforePlay, Configure.BAIDU_VIDEO_ID); 151 | mBaiduBeforeAd.setListener(new VideoBeforeListener(this, mMediaController, mBaiduBeforeAd, mVideoView)); 152 | 153 | mBaiduPauseAd = new InterstitialAd(this, AdSize.InterstitialForVideoPausePlay, Configure.BAIDU_VIDEO_ID); 154 | mBaiduPauseAd.setListener(new VideoPauseListener(mBaiduPauseAd, mVideoView)); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /app/src/com/ishow/sample/videoplayer/constant/Configure.java: -------------------------------------------------------------------------------- 1 | package com.ishow.sample.videoplayer.constant; 2 | 3 | /** 4 | * Created by Bright.Yu on 2016/3/17. 5 | */ 6 | public class Configure { 7 | /** 8 | * 百度广告 是否打开使用 9 | */ 10 | public static final boolean SHOW_BAIDU_AD = true; 11 | /** 12 | * 百度Demo中的ID:2058622,个人ID:2431064 13 | */ 14 | public static final String BAIDU_SPLASH_ID = "2058622"; 15 | 16 | /** 17 | * 百度Demo中的ID:2058626 ,个人ID:2431069 18 | */ 19 | public static final String BAIDU_VIDEO_ID = "2058626"; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /app/src/com/ishow/sample/videoplayer/listener/VideoBeforeListener.java: -------------------------------------------------------------------------------- 1 | package com.ishow.sample.videoplayer.listener; 2 | 3 | import android.app.Activity; 4 | import android.util.Log; 5 | 6 | import com.baidu.mobads.InterstitialAd; 7 | import com.baidu.mobads.InterstitialAdListener; 8 | import com.ishow.videoplayer.widget.MediaController; 9 | import com.ishow.videoplayer.widget.media.VideoView; 10 | 11 | /** 12 | * Created by yuhaiyang on 2016/3/8. 13 | */ 14 | public class VideoBeforeListener implements InterstitialAdListener { 15 | private static final String TAG = "VideoBeforeListener"; 16 | private InterstitialAd mBaiduAd; 17 | private VideoView mVideoView; 18 | private Activity mActivity; 19 | private MediaController mMediaController; 20 | 21 | public VideoBeforeListener(Activity activity, MediaController controller, InterstitialAd ad, VideoView videoView) { 22 | mBaiduAd = ad; 23 | mVideoView = videoView; 24 | 25 | mActivity = activity; 26 | mMediaController = controller; 27 | if(!mBaiduAd.isAdReady()) { 28 | mBaiduAd.loadAdForVideoApp(mVideoView.getWidth(), mVideoView.getHeight()); 29 | }else{ 30 | mBaiduAd.showAdInParentForVideoApp(mActivity, mMediaController.getAdView()); 31 | } 32 | } 33 | 34 | @Override 35 | public void onAdReady() { 36 | Log.i(TAG, "onAdReady: "); 37 | mBaiduAd.showAdInParentForVideoApp(mActivity, mMediaController.getAdView()); 38 | } 39 | 40 | @Override 41 | public void onAdPresent() { 42 | Log.i(TAG, "onAdPresent: "); 43 | mVideoView.pause(); 44 | } 45 | 46 | @Override 47 | public void onAdClick(InterstitialAd interstitialAd) { 48 | Log.i(TAG, "onAdClick: "); 49 | } 50 | 51 | @Override 52 | public void onAdDismissed() { 53 | Log.i(TAG, "onAdDismissed: "); 54 | mVideoView.start(); 55 | } 56 | 57 | @Override 58 | public void onAdFailed(String s) { 59 | Log.i(TAG, "onAdFailed: "); 60 | mVideoView.start(); 61 | mBaiduAd.loadAdForVideoApp(mVideoView.getWidth(), mVideoView.getHeight()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/com/ishow/sample/videoplayer/listener/VideoPauseListener.java: -------------------------------------------------------------------------------- 1 | package com.ishow.sample.videoplayer.listener; 2 | 3 | import android.util.Log; 4 | 5 | import com.baidu.mobads.InterstitialAd; 6 | import com.baidu.mobads.InterstitialAdListener; 7 | import com.ishow.videoplayer.widget.media.VideoView; 8 | 9 | /** 10 | * Created by yuhaiyang on 2016/3/8. 11 | */ 12 | public class VideoPauseListener implements InterstitialAdListener { 13 | private static final String TAG = "VideoPauseListener"; 14 | private InterstitialAd mBaiduAd; 15 | private VideoView mVideoView; 16 | 17 | public VideoPauseListener(InterstitialAd ad, VideoView videoView) { 18 | mBaiduAd = ad; 19 | mVideoView = videoView; 20 | } 21 | 22 | @Override 23 | public void onAdReady() { 24 | Log.i(TAG, "onAdReady: "); 25 | } 26 | 27 | @Override 28 | public void onAdPresent() { 29 | Log.i(TAG, "onAdPresent: "); 30 | } 31 | 32 | @Override 33 | public void onAdClick(InterstitialAd interstitialAd) { 34 | Log.i(TAG, "onAdClick: "); 35 | } 36 | 37 | @Override 38 | public void onAdDismissed() { 39 | Log.i(TAG, "onAdDismissed: "); 40 | mVideoView.setShowAction(); 41 | mBaiduAd.loadAdForVideoApp(mVideoView.getWidth(), mVideoView.getHeight()); 42 | } 43 | 44 | @Override 45 | public void onAdFailed(String s) { 46 | Log.i(TAG, "onAdFailed: "); 47 | mBaiduAd.loadAdForVideoApp(mVideoView.getWidth(), mVideoView.getHeight()); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The yuhaiyang Android Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @author: y.haiyang@qq.com 17 | */ 18 | 19 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 20 | 21 | buildscript { 22 | repositories { 23 | jcenter() 24 | google() 25 | } 26 | dependencies { 27 | classpath 'com.android.tools.build:gradle:3.1.1' 28 | } 29 | } 30 | 31 | allprojects { 32 | repositories { 33 | jcenter() 34 | google() 35 | } 36 | 37 | // Javadoc设定为UTF-8了 38 | tasks.withType(Javadoc) { 39 | options.addStringOption('Xdoclint:none', '-quiet') 40 | options.addStringOption('encoding', 'UTF-8') 41 | } 42 | } 43 | 44 | task clean(type: Delete) { 45 | delete rootProject.buildDir 46 | } 47 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2016 The yuhaiyang Android Source Project 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | # @author: y.haiyang@qq.com 17 | # 18 | 19 | # Project-wide Gradle settings. 20 | 21 | # IDE (e.g. Android Studio) users: 22 | # Gradle settings configured through the IDE *will override* 23 | # any settings specified in this file. 24 | 25 | # For more details on how to configure your build environment visit 26 | # http://www.gradle.org/docs/current/userguide/build_environment.html 27 | 28 | # Specifies the JVM arguments used for the daemon process. 29 | # The setting is particularly useful for tweaking memory settings. 30 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 31 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 32 | 33 | # When configured, Gradle will run in incubating parallel mode. 34 | # This option should only be used with decoupled projects. More details, visit 35 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 36 | # org.gradle.parallel=true 37 | ############################################################################# 38 | # 通用 配置 39 | ############################################################################# 40 | # 版本号 **************************重要配置一定要长**************************** 41 | JCENTER_VERSION=0.0.3 42 | 43 | VERSION_NAME=0.0.3 44 | # 最低SDK版本 45 | MIN_SDK_VERSION=15 46 | # 目标编译版本 47 | TARGET_SDK_VERSION=22 48 | #编译版本 49 | COMPILE_SDK_VERSION=27 50 | # 编译工具版本 51 | BUILD_TOOLS_VERSION=27.0.3 52 | # Android 版本包(去除V4和V7 其他的暂用这一个) 53 | ANDOID_SUPPORT_VERSION=27.1.1 54 | # Android V4包的版本 55 | SUPPORT_V4_VERSION=27.1.1 56 | # Android V7包的版本 57 | SUPPORT_V7_VERSION=27.1.1 58 | ############################################################################# 59 | # 正式发布版本 配置 60 | ############################################################################# 61 | # 签名配置 62 | RELEASE_STOREFILE=keystore/keystore.jks 63 | RELEASE_STORE_PASSWORD=123456789 64 | RELEASE_KEY_ALIAS=yuhaiyang 65 | RELEASE_KEY_PASSWORD=123456789 66 | 67 | # applicationId 68 | RELEASE_APPLICATION_ID=com.ishow.sample.videoplayer 69 | ############################################################################# 70 | # 测试发布版本 配置 71 | ############################################################################# 72 | # applicationId 73 | DEV_APPLICATION_ID=com.ishow.sample.videoplayer 74 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-show/android-IJKplayerSample/a02ba1a4bc838ed028d97dc51a2d6b1ed7bed623/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Aug 16 18:15:26 GMT+08:00 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /images/01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-show/android-IJKplayerSample/a02ba1a4bc838ed028d97dc51a2d6b1ed7bed623/images/01.gif -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The yuhaiyang Android Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @author: y.haiyang@qq.com 17 | */ 18 | 19 | include ':videoplayer' 20 | include ':app' 21 | 22 | -------------------------------------------------------------------------------- /videoplayer/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | -------------------------------------------------------------------------------- /videoplayer/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The yuhaiyang Android Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @author: y.haiyang@qq.com 17 | */ 18 | 19 | apply plugin: 'com.android.library' 20 | 21 | android { 22 | compileSdkVersion COMPILE_SDK_VERSION as int 23 | buildToolsVersion BUILD_TOOLS_VERSION 24 | 25 | defaultConfig { 26 | minSdkVersion MIN_SDK_VERSION as int 27 | targetSdkVersion TARGET_SDK_VERSION as int 28 | } 29 | 30 | 31 | sourceSets { 32 | main { 33 | manifest.srcFile 'AndroidManifest.xml' 34 | java.srcDirs = ['src'] 35 | resources.srcDirs = ['src'] 36 | aidl.srcDirs = ['src'] 37 | renderscript.srcDirs = ['src'] 38 | res.srcDirs = ['res'] 39 | assets.srcDirs = ['assets'] 40 | jniLibs.srcDirs = ['libs'] 41 | } 42 | 43 | debug.setRoot('build-types/debug') 44 | release.setRoot('build-types/release') 45 | } 46 | buildToolsVersion '27.0.3' 47 | } 48 | 49 | // 编译的时候使用UTF-8 50 | tasks.withType(JavaCompile) { 51 | options.encoding = "UTF-8" 52 | } 53 | 54 | dependencies { 55 | api fileTree(dir: 'libs', include: ['*.jar']) 56 | 57 | api "com.android.support:appcompat-v7:${SUPPORT_V7_VERSION}" 58 | api "com.android.support:support-annotations:${SUPPORT_V7_VERSION}" 59 | 60 | api 'tv.danmaku.ijk.media:ijkplayer-exo:0.5.1' 61 | // required, enough for most devices. 62 | api 'tv.danmaku.ijk.media:ijkplayer-java:0.5.1' 63 | api 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.5.1' 64 | // Other ABIs: optional 65 | //compile 'tv.danmaku.ijk.media:ijkplayer-armv5:0.4.5.1' 66 | //compile 'tv.danmaku.ijk.media:ijkplayer-arm64:0.4.5.1' 67 | //compile 'tv.danmaku.ijk.media:ijkplayer-x86:0.4.5.1' 68 | } 69 | -------------------------------------------------------------------------------- /videoplayer/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /opt/android/ADK/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /videoplayer/res/drawable-xhdpi/ic_backward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-show/android-IJKplayerSample/a02ba1a4bc838ed028d97dc51a2d6b1ed7bed623/videoplayer/res/drawable-xhdpi/ic_backward.png -------------------------------------------------------------------------------- /videoplayer/res/drawable-xhdpi/ic_forward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-show/android-IJKplayerSample/a02ba1a4bc838ed028d97dc51a2d6b1ed7bed623/videoplayer/res/drawable-xhdpi/ic_forward.png -------------------------------------------------------------------------------- /videoplayer/res/drawable-xhdpi/ic_play_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-show/android-IJKplayerSample/a02ba1a4bc838ed028d97dc51a2d6b1ed7bed623/videoplayer/res/drawable-xhdpi/ic_play_pause.png -------------------------------------------------------------------------------- /videoplayer/res/drawable-xhdpi/ic_play_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-show/android-IJKplayerSample/a02ba1a4bc838ed028d97dc51a2d6b1ed7bed623/videoplayer/res/drawable-xhdpi/ic_play_play.png -------------------------------------------------------------------------------- /videoplayer/res/drawable-xhdpi/ic_to_fullscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-show/android-IJKplayerSample/a02ba1a4bc838ed028d97dc51a2d6b1ed7bed623/videoplayer/res/drawable-xhdpi/ic_to_fullscreen.png -------------------------------------------------------------------------------- /videoplayer/res/drawable-xhdpi/ic_to_smallscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-show/android-IJKplayerSample/a02ba1a4bc838ed028d97dc51a2d6b1ed7bed623/videoplayer/res/drawable-xhdpi/ic_to_smallscreen.png -------------------------------------------------------------------------------- /videoplayer/res/drawable-xhdpi/ic_video_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-show/android-IJKplayerSample/a02ba1a4bc838ed028d97dc51a2d6b1ed7bed623/videoplayer/res/drawable-xhdpi/ic_video_back.png -------------------------------------------------------------------------------- /videoplayer/res/drawable-xhdpi/ic_video_loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-show/android-IJKplayerSample/a02ba1a4bc838ed028d97dc51a2d6b1ed7bed623/videoplayer/res/drawable-xhdpi/ic_video_loading.png -------------------------------------------------------------------------------- /videoplayer/res/drawable-xhdpi/ic_vidoe_play_next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-show/android-IJKplayerSample/a02ba1a4bc838ed028d97dc51a2d6b1ed7bed623/videoplayer/res/drawable-xhdpi/ic_vidoe_play_next.png -------------------------------------------------------------------------------- /videoplayer/res/drawable-xhdpi/normal_panel_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-show/android-IJKplayerSample/a02ba1a4bc838ed028d97dc51a2d6b1ed7bed623/videoplayer/res/drawable-xhdpi/normal_panel_bg.9.png -------------------------------------------------------------------------------- /videoplayer/res/drawable-xhdpi/progress_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-show/android-IJKplayerSample/a02ba1a4bc838ed028d97dc51a2d6b1ed7bed623/videoplayer/res/drawable-xhdpi/progress_thumb.png -------------------------------------------------------------------------------- /videoplayer/res/drawable/progress_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /videoplayer/res/drawable/video_loading.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 25 | -------------------------------------------------------------------------------- /videoplayer/res/layout/media_controller.xml: -------------------------------------------------------------------------------- 1 | 18 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /videoplayer/res/layout/media_controller_ad.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 25 | -------------------------------------------------------------------------------- /videoplayer/res/layout/media_controller_loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | 21 | 22 | 27 | 28 | 29 | 36 | 37 | -------------------------------------------------------------------------------- /videoplayer/res/layout/media_controller_normal.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 25 | 26 | 32 | 33 | 40 | 41 | 48 | 49 | 50 | 51 | 52 | 59 | 60 | 69 | 70 | 76 | 77 | 82 | 83 | 84 | 93 | 94 | 107 | 108 | 117 | 118 | 127 | 128 | -------------------------------------------------------------------------------- /videoplayer/res/layout/media_controller_slide.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 22 | 23 | 24 | 29 | 30 | 38 | 39 | 45 | 46 | 51 | 52 | 58 | 59 | 67 | 68 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /videoplayer/res/values-sw240dp/dimen.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 0.67dp 20 | 1.33dp 21 | 2.00dp 22 | 2.67dp 23 | 3.33dp 24 | 4.00dp 25 | 4.67dp 26 | 5.33dp 27 | 6.00dp 28 | 6.67dp 29 | 7.33dp 30 | 8.00dp 31 | 8.67dp 32 | 9.33dp 33 | 10.00dp 34 | 10.67dp 35 | 11.33dp 36 | 12.00dp 37 | 12.67dp 38 | 13.33dp 39 | 14.00dp 40 | 14.67dp 41 | 15.33dp 42 | 16.00dp 43 | 16.67dp 44 | 17.33dp 45 | 18.00dp 46 | 18.67dp 47 | 19.33dp 48 | 20.00dp 49 | 20.67dp 50 | 21.33dp 51 | 22.00dp 52 | 22.67dp 53 | 23.33dp 54 | 24.00dp 55 | 24.67dp 56 | 25.33dp 57 | 26.00dp 58 | 26.67dp 59 | 27.33dp 60 | 28.00dp 61 | 28.67dp 62 | 29.33dp 63 | 30.00dp 64 | 30.67dp 65 | 31.33dp 66 | 32.00dp 67 | 32.67dp 68 | 33.33dp 69 | 34.00dp 70 | 34.67dp 71 | 35.33dp 72 | 36.00dp 73 | 36.67dp 74 | 37.33dp 75 | 38.00dp 76 | 38.67dp 77 | 39.33dp 78 | 40.00dp 79 | 40.67dp 80 | 41.33dp 81 | 42.00dp 82 | 42.67dp 83 | 43.33dp 84 | 44.00dp 85 | 44.67dp 86 | 45.33dp 87 | 46.00dp 88 | 46.67dp 89 | 47.33dp 90 | 48.00dp 91 | 48.67dp 92 | 49.33dp 93 | 50.00dp 94 | 50.67dp 95 | 51.33dp 96 | 52.00dp 97 | 52.67dp 98 | 53.33dp 99 | 54.00dp 100 | 54.67dp 101 | 55.33dp 102 | 56.00dp 103 | 56.67dp 104 | 57.33dp 105 | 58.00dp 106 | 58.67dp 107 | 59.33dp 108 | 60.00dp 109 | 60.67dp 110 | 61.33dp 111 | 62.00dp 112 | 62.67dp 113 | 63.33dp 114 | 64.00dp 115 | 64.67dp 116 | 65.33dp 117 | 66.00dp 118 | 66.67dp 119 | 67.33dp 120 | 68.00dp 121 | 68.67dp 122 | 69.33dp 123 | 70.00dp 124 | 70.67dp 125 | 71.33dp 126 | 72.00dp 127 | 72.67dp 128 | 73.33dp 129 | 74.00dp 130 | 74.67dp 131 | 75.33dp 132 | 76.00dp 133 | 76.67dp 134 | 77.33dp 135 | 78.00dp 136 | 78.67dp 137 | 79.33dp 138 | 80.00dp 139 | 80.67dp 140 | 81.33dp 141 | 82.00dp 142 | 82.67dp 143 | 83.33dp 144 | 84.00dp 145 | 84.67dp 146 | 85.33dp 147 | 86.00dp 148 | 86.67dp 149 | 87.33dp 150 | 88.00dp 151 | 88.67dp 152 | 89.33dp 153 | 90.00dp 154 | 90.67dp 155 | 91.33dp 156 | 92.00dp 157 | 92.67dp 158 | 93.33dp 159 | 94.00dp 160 | 94.67dp 161 | 95.33dp 162 | 96.00dp 163 | 96.67dp 164 | 97.33dp 165 | 98.00dp 166 | 98.67dp 167 | 99.33dp 168 | 100.00dp 169 | 100.67dp 170 | 101.33dp 171 | 102.00dp 172 | 102.67dp 173 | 103.33dp 174 | 104.00dp 175 | 104.67dp 176 | 105.33dp 177 | 106.00dp 178 | 106.67dp 179 | 107.33dp 180 | 108.00dp 181 | 108.67dp 182 | 109.33dp 183 | 110.00dp 184 | 110.67dp 185 | 111.33dp 186 | 112.00dp 187 | 112.67dp 188 | 113.33dp 189 | 114.00dp 190 | 114.67dp 191 | 115.33dp 192 | 116.00dp 193 | 116.67dp 194 | 117.33dp 195 | 118.00dp 196 | 118.67dp 197 | 119.33dp 198 | 120.00dp 199 | 120.67dp 200 | 121.33dp 201 | 122.00dp 202 | 122.67dp 203 | 123.33dp 204 | 124.00dp 205 | 124.67dp 206 | 125.33dp 207 | 126.00dp 208 | 126.67dp 209 | 127.33dp 210 | 128.00dp 211 | 128.67dp 212 | 129.33dp 213 | 130.00dp 214 | 130.67dp 215 | 131.33dp 216 | 132.00dp 217 | 132.67dp 218 | 133.33dp 219 | 134.00dp 220 | 134.67dp 221 | 135.33dp 222 | 136.00dp 223 | 136.67dp 224 | 137.33dp 225 | 138.00dp 226 | 138.67dp 227 | 139.33dp 228 | 140.00dp 229 | 140.67dp 230 | 141.33dp 231 | 142.00dp 232 | 142.67dp 233 | 143.33dp 234 | 144.00dp 235 | 144.67dp 236 | 145.33dp 237 | 146.00dp 238 | 146.67dp 239 | 147.33dp 240 | 148.00dp 241 | 148.67dp 242 | 149.33dp 243 | 150.00dp 244 | 150.67dp 245 | 151.33dp 246 | 152.00dp 247 | 152.67dp 248 | 153.33dp 249 | 154.00dp 250 | 154.67dp 251 | 155.33dp 252 | 156.00dp 253 | 156.67dp 254 | 157.33dp 255 | 158.00dp 256 | 158.67dp 257 | 159.33dp 258 | 160.00dp 259 | 160.67dp 260 | 161.33dp 261 | 162.00dp 262 | 162.67dp 263 | 163.33dp 264 | 164.00dp 265 | 164.67dp 266 | 165.33dp 267 | 166.00dp 268 | 166.67dp 269 | 167.33dp 270 | 168.00dp 271 | 168.67dp 272 | 169.33dp 273 | 170.00dp 274 | 170.67dp 275 | 171.33dp 276 | 172.00dp 277 | 172.67dp 278 | 173.33dp 279 | 174.00dp 280 | 174.67dp 281 | 175.33dp 282 | 176.00dp 283 | 176.67dp 284 | 177.33dp 285 | 178.00dp 286 | 178.67dp 287 | 179.33dp 288 | 180.00dp 289 | 180.67dp 290 | 181.33dp 291 | 182.00dp 292 | 182.67dp 293 | 183.33dp 294 | 184.00dp 295 | 184.67dp 296 | 185.33dp 297 | 186.00dp 298 | 186.67dp 299 | 187.33dp 300 | 188.00dp 301 | 188.67dp 302 | 189.33dp 303 | 190.00dp 304 | 190.67dp 305 | 191.33dp 306 | 192.00dp 307 | 192.67dp 308 | 193.33dp 309 | 194.00dp 310 | 194.67dp 311 | 195.33dp 312 | 196.00dp 313 | 196.67dp 314 | 197.33dp 315 | 198.00dp 316 | 198.67dp 317 | 199.33dp 318 | 200.00dp 319 | 200.67dp 320 | 201.33dp 321 | 202.00dp 322 | 202.67dp 323 | 203.33dp 324 | 204.00dp 325 | 204.67dp 326 | 205.33dp 327 | 206.00dp 328 | 206.67dp 329 | 207.33dp 330 | 208.00dp 331 | 208.67dp 332 | 209.33dp 333 | 210.00dp 334 | 210.67dp 335 | 211.33dp 336 | 212.00dp 337 | 212.67dp 338 | 213.33dp 339 | 214.00dp 340 | 214.67dp 341 | 215.33dp 342 | 216.00dp 343 | 216.67dp 344 | 217.33dp 345 | 218.00dp 346 | 218.67dp 347 | 219.33dp 348 | 220.00dp 349 | 220.67dp 350 | 221.33dp 351 | 222.00dp 352 | 222.67dp 353 | 223.33dp 354 | 224.00dp 355 | 224.67dp 356 | 225.33dp 357 | 226.00dp 358 | 226.67dp 359 | 227.33dp 360 | 228.00dp 361 | 228.67dp 362 | 229.33dp 363 | 230.00dp 364 | 230.67dp 365 | 231.33dp 366 | 232.00dp 367 | 232.67dp 368 | 233.33dp 369 | 234.00dp 370 | 234.67dp 371 | 235.33dp 372 | 236.00dp 373 | 236.67dp 374 | 237.33dp 375 | 238.00dp 376 | 238.67dp 377 | 239.33dp 378 | 240.00dp 379 | 240.67dp 380 | 241.33dp 381 | 242.00dp 382 | 242.67dp 383 | 243.33dp 384 | 244.00dp 385 | 244.67dp 386 | 245.33dp 387 | 246.00dp 388 | 246.67dp 389 | 247.33dp 390 | 248.00dp 391 | 248.67dp 392 | 249.33dp 393 | 250.00dp 394 | 250.67dp 395 | 251.33dp 396 | 252.00dp 397 | 252.67dp 398 | 253.33dp 399 | 254.00dp 400 | 254.67dp 401 | 255.33dp 402 | 256.00dp 403 | 256.67dp 404 | 257.33dp 405 | 258.00dp 406 | 258.67dp 407 | 259.33dp 408 | 260.00dp 409 | 260.67dp 410 | 261.33dp 411 | 262.00dp 412 | 262.67dp 413 | 263.33dp 414 | 264.00dp 415 | 264.67dp 416 | 265.33dp 417 | 266.00dp 418 | 266.67dp 419 | 267.33dp 420 | 268.00dp 421 | 268.67dp 422 | 269.33dp 423 | 270.00dp 424 | 270.67dp 425 | 271.33dp 426 | 272.00dp 427 | 272.67dp 428 | 273.33dp 429 | 274.00dp 430 | 274.67dp 431 | 275.33dp 432 | 276.00dp 433 | 276.67dp 434 | 277.33dp 435 | 278.00dp 436 | 278.67dp 437 | 279.33dp 438 | 280.00dp 439 | 280.67dp 440 | 281.33dp 441 | 282.00dp 442 | 282.67dp 443 | 283.33dp 444 | 284.00dp 445 | 284.67dp 446 | 285.33dp 447 | 286.00dp 448 | 286.67dp 449 | 287.33dp 450 | 288.00dp 451 | 288.67dp 452 | 289.33dp 453 | 290.00dp 454 | 290.67dp 455 | 291.33dp 456 | 292.00dp 457 | 292.67dp 458 | 293.33dp 459 | 294.00dp 460 | 294.67dp 461 | 295.33dp 462 | 296.00dp 463 | 296.67dp 464 | 297.33dp 465 | 298.00dp 466 | 298.67dp 467 | 299.33dp 468 | 300.00dp 469 | 300.67dp 470 | 301.33dp 471 | 302.00dp 472 | 302.67dp 473 | 303.33dp 474 | 304.00dp 475 | 304.67dp 476 | 305.33dp 477 | 306.00dp 478 | 306.67dp 479 | 307.33dp 480 | 308.00dp 481 | 308.67dp 482 | 309.33dp 483 | 310.00dp 484 | 310.67dp 485 | 311.33dp 486 | 312.00dp 487 | 312.67dp 488 | 313.33dp 489 | 314.00dp 490 | 314.67dp 491 | 315.33dp 492 | 316.00dp 493 | 316.67dp 494 | 317.33dp 495 | 318.00dp 496 | 318.67dp 497 | 319.33dp 498 | 320.00dp 499 | 320.67dp 500 | 321.33dp 501 | 322.00dp 502 | 322.67dp 503 | 323.33dp 504 | 324.00dp 505 | 324.67dp 506 | 325.33dp 507 | 326.00dp 508 | 326.67dp 509 | 327.33dp 510 | 328.00dp 511 | 328.67dp 512 | 329.33dp 513 | 330.00dp 514 | 330.67dp 515 | 331.33dp 516 | 332.00dp 517 | 332.67dp 518 | 333.33dp 519 | -------------------------------------------------------------------------------- /videoplayer/res/values-sw320dp/dimen.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 0.89dp 20 | 1.78dp 21 | 2.67dp 22 | 3.56dp 23 | 4.44dp 24 | 5.33dp 25 | 6.22dp 26 | 7.11dp 27 | 8.00dp 28 | 8.89dp 29 | 9.78dp 30 | 10.67dp 31 | 11.56dp 32 | 12.44dp 33 | 13.33dp 34 | 14.22dp 35 | 15.11dp 36 | 16.00dp 37 | 16.89dp 38 | 17.78dp 39 | 18.67dp 40 | 19.56dp 41 | 20.44dp 42 | 21.33dp 43 | 22.22dp 44 | 23.11dp 45 | 24.00dp 46 | 24.89dp 47 | 25.78dp 48 | 26.67dp 49 | 27.56dp 50 | 28.44dp 51 | 29.33dp 52 | 30.22dp 53 | 31.11dp 54 | 32.00dp 55 | 32.89dp 56 | 33.78dp 57 | 34.67dp 58 | 35.56dp 59 | 36.44dp 60 | 37.33dp 61 | 38.22dp 62 | 39.11dp 63 | 40.00dp 64 | 40.89dp 65 | 41.78dp 66 | 42.67dp 67 | 43.56dp 68 | 44.44dp 69 | 45.33dp 70 | 46.22dp 71 | 47.11dp 72 | 48.00dp 73 | 48.89dp 74 | 49.78dp 75 | 50.67dp 76 | 51.56dp 77 | 52.44dp 78 | 53.33dp 79 | 54.22dp 80 | 55.11dp 81 | 56.00dp 82 | 56.89dp 83 | 57.78dp 84 | 58.67dp 85 | 59.56dp 86 | 60.44dp 87 | 61.33dp 88 | 62.22dp 89 | 63.11dp 90 | 64.00dp 91 | 64.89dp 92 | 65.78dp 93 | 66.67dp 94 | 67.56dp 95 | 68.44dp 96 | 69.33dp 97 | 70.22dp 98 | 71.11dp 99 | 72.00dp 100 | 72.89dp 101 | 73.78dp 102 | 74.67dp 103 | 75.56dp 104 | 76.44dp 105 | 77.33dp 106 | 78.22dp 107 | 79.11dp 108 | 80.00dp 109 | 80.89dp 110 | 81.78dp 111 | 82.67dp 112 | 83.56dp 113 | 84.44dp 114 | 85.33dp 115 | 86.22dp 116 | 87.11dp 117 | 88.00dp 118 | 88.89dp 119 | 89.78dp 120 | 90.67dp 121 | 91.56dp 122 | 92.44dp 123 | 93.33dp 124 | 94.22dp 125 | 95.11dp 126 | 96.00dp 127 | 96.89dp 128 | 97.78dp 129 | 98.67dp 130 | 99.56dp 131 | 100.44dp 132 | 101.33dp 133 | 102.22dp 134 | 103.11dp 135 | 104.00dp 136 | 104.89dp 137 | 105.78dp 138 | 106.67dp 139 | 107.56dp 140 | 108.44dp 141 | 109.33dp 142 | 110.22dp 143 | 111.11dp 144 | 112.00dp 145 | 112.89dp 146 | 113.78dp 147 | 114.67dp 148 | 115.56dp 149 | 116.44dp 150 | 117.33dp 151 | 118.22dp 152 | 119.11dp 153 | 120.00dp 154 | 120.89dp 155 | 121.78dp 156 | 122.67dp 157 | 123.56dp 158 | 124.44dp 159 | 125.33dp 160 | 126.22dp 161 | 127.11dp 162 | 128.00dp 163 | 128.89dp 164 | 129.78dp 165 | 130.67dp 166 | 131.56dp 167 | 132.44dp 168 | 133.33dp 169 | 134.22dp 170 | 135.11dp 171 | 136.00dp 172 | 136.89dp 173 | 137.78dp 174 | 138.67dp 175 | 139.56dp 176 | 140.44dp 177 | 141.33dp 178 | 142.22dp 179 | 143.11dp 180 | 144.00dp 181 | 144.89dp 182 | 145.78dp 183 | 146.67dp 184 | 147.56dp 185 | 148.44dp 186 | 149.33dp 187 | 150.22dp 188 | 151.11dp 189 | 152.00dp 190 | 152.89dp 191 | 153.78dp 192 | 154.67dp 193 | 155.56dp 194 | 156.44dp 195 | 157.33dp 196 | 158.22dp 197 | 159.11dp 198 | 160.00dp 199 | 160.89dp 200 | 161.78dp 201 | 162.67dp 202 | 163.56dp 203 | 164.44dp 204 | 165.33dp 205 | 166.22dp 206 | 167.11dp 207 | 168.00dp 208 | 168.89dp 209 | 169.78dp 210 | 170.67dp 211 | 171.56dp 212 | 172.44dp 213 | 173.33dp 214 | 174.22dp 215 | 175.11dp 216 | 176.00dp 217 | 176.89dp 218 | 177.78dp 219 | 178.67dp 220 | 179.56dp 221 | 180.44dp 222 | 181.33dp 223 | 182.22dp 224 | 183.11dp 225 | 184.00dp 226 | 184.89dp 227 | 185.78dp 228 | 186.67dp 229 | 187.56dp 230 | 188.44dp 231 | 189.33dp 232 | 190.22dp 233 | 191.11dp 234 | 192.00dp 235 | 192.89dp 236 | 193.78dp 237 | 194.67dp 238 | 195.56dp 239 | 196.44dp 240 | 197.33dp 241 | 198.22dp 242 | 199.11dp 243 | 200.00dp 244 | 200.89dp 245 | 201.78dp 246 | 202.67dp 247 | 203.56dp 248 | 204.44dp 249 | 205.33dp 250 | 206.22dp 251 | 207.11dp 252 | 208.00dp 253 | 208.89dp 254 | 209.78dp 255 | 210.67dp 256 | 211.56dp 257 | 212.44dp 258 | 213.33dp 259 | 214.22dp 260 | 215.11dp 261 | 216.00dp 262 | 216.89dp 263 | 217.78dp 264 | 218.67dp 265 | 219.56dp 266 | 220.44dp 267 | 221.33dp 268 | 222.22dp 269 | 223.11dp 270 | 224.00dp 271 | 224.89dp 272 | 225.78dp 273 | 226.67dp 274 | 227.56dp 275 | 228.44dp 276 | 229.33dp 277 | 230.22dp 278 | 231.11dp 279 | 232.00dp 280 | 232.89dp 281 | 233.78dp 282 | 234.67dp 283 | 235.56dp 284 | 236.44dp 285 | 237.33dp 286 | 238.22dp 287 | 239.11dp 288 | 240.00dp 289 | 240.89dp 290 | 241.78dp 291 | 242.67dp 292 | 243.56dp 293 | 244.44dp 294 | 245.33dp 295 | 246.22dp 296 | 247.11dp 297 | 248.00dp 298 | 248.89dp 299 | 249.78dp 300 | 250.67dp 301 | 251.56dp 302 | 252.44dp 303 | 253.33dp 304 | 254.22dp 305 | 255.11dp 306 | 256.00dp 307 | 256.89dp 308 | 257.78dp 309 | 258.67dp 310 | 259.56dp 311 | 260.44dp 312 | 261.33dp 313 | 262.22dp 314 | 263.11dp 315 | 264.00dp 316 | 264.89dp 317 | 265.78dp 318 | 266.67dp 319 | 267.56dp 320 | 268.44dp 321 | 269.33dp 322 | 270.22dp 323 | 271.11dp 324 | 272.00dp 325 | 272.89dp 326 | 273.78dp 327 | 274.67dp 328 | 275.56dp 329 | 276.44dp 330 | 277.33dp 331 | 278.22dp 332 | 279.11dp 333 | 280.00dp 334 | 280.89dp 335 | 281.78dp 336 | 282.67dp 337 | 283.56dp 338 | 284.44dp 339 | 285.33dp 340 | 286.22dp 341 | 287.11dp 342 | 288.00dp 343 | 288.89dp 344 | 289.78dp 345 | 290.67dp 346 | 291.56dp 347 | 292.44dp 348 | 293.33dp 349 | 294.22dp 350 | 295.11dp 351 | 296.00dp 352 | 296.89dp 353 | 297.78dp 354 | 298.67dp 355 | 299.56dp 356 | 300.44dp 357 | 301.33dp 358 | 302.22dp 359 | 303.11dp 360 | 304.00dp 361 | 304.89dp 362 | 305.78dp 363 | 306.67dp 364 | 307.56dp 365 | 308.44dp 366 | 309.33dp 367 | 310.22dp 368 | 311.11dp 369 | 312.00dp 370 | 312.89dp 371 | 313.78dp 372 | 314.67dp 373 | 315.56dp 374 | 316.44dp 375 | 317.33dp 376 | 318.22dp 377 | 319.11dp 378 | 320.00dp 379 | 320.89dp 380 | 321.78dp 381 | 322.67dp 382 | 323.56dp 383 | 324.44dp 384 | 325.33dp 385 | 326.22dp 386 | 327.11dp 387 | 328.00dp 388 | 328.89dp 389 | 329.78dp 390 | 330.67dp 391 | 331.56dp 392 | 332.44dp 393 | 333.33dp 394 | 334.22dp 395 | 335.11dp 396 | 336.00dp 397 | 336.89dp 398 | 337.78dp 399 | 338.67dp 400 | 339.56dp 401 | 340.44dp 402 | 341.33dp 403 | 342.22dp 404 | 343.11dp 405 | 344.00dp 406 | 344.89dp 407 | 345.78dp 408 | 346.67dp 409 | 347.56dp 410 | 348.44dp 411 | 349.33dp 412 | 350.22dp 413 | 351.11dp 414 | 352.00dp 415 | 352.89dp 416 | 353.78dp 417 | 354.67dp 418 | 355.56dp 419 | 356.44dp 420 | 357.33dp 421 | 358.22dp 422 | 359.11dp 423 | 360.00dp 424 | 360.89dp 425 | 361.78dp 426 | 362.67dp 427 | 363.56dp 428 | 364.44dp 429 | 365.33dp 430 | 366.22dp 431 | 367.11dp 432 | 368.00dp 433 | 368.89dp 434 | 369.78dp 435 | 370.67dp 436 | 371.56dp 437 | 372.44dp 438 | 373.33dp 439 | 374.22dp 440 | 375.11dp 441 | 376.00dp 442 | 376.89dp 443 | 377.78dp 444 | 378.67dp 445 | 379.56dp 446 | 380.44dp 447 | 381.33dp 448 | 382.22dp 449 | 383.11dp 450 | 384.00dp 451 | 384.89dp 452 | 385.78dp 453 | 386.67dp 454 | 387.56dp 455 | 388.44dp 456 | 389.33dp 457 | 390.22dp 458 | 391.11dp 459 | 392.00dp 460 | 392.89dp 461 | 393.78dp 462 | 394.67dp 463 | 395.56dp 464 | 396.44dp 465 | 397.33dp 466 | 398.22dp 467 | 399.11dp 468 | 400.00dp 469 | 400.89dp 470 | 401.78dp 471 | 402.67dp 472 | 403.56dp 473 | 404.44dp 474 | 405.33dp 475 | 406.22dp 476 | 407.11dp 477 | 408.00dp 478 | 408.89dp 479 | 409.78dp 480 | 410.67dp 481 | 411.56dp 482 | 412.44dp 483 | 413.33dp 484 | 414.22dp 485 | 415.11dp 486 | 416.00dp 487 | 416.89dp 488 | 417.78dp 489 | 418.67dp 490 | 419.56dp 491 | 420.44dp 492 | 421.33dp 493 | 422.22dp 494 | 423.11dp 495 | 424.00dp 496 | 424.89dp 497 | 425.78dp 498 | 426.67dp 499 | 427.56dp 500 | 428.44dp 501 | 429.33dp 502 | 430.22dp 503 | 431.11dp 504 | 432.00dp 505 | 432.89dp 506 | 433.78dp 507 | 434.67dp 508 | 435.56dp 509 | 436.44dp 510 | 437.33dp 511 | 438.22dp 512 | 439.11dp 513 | 440.00dp 514 | 440.89dp 515 | 441.78dp 516 | 442.67dp 517 | 443.56dp 518 | 444.44dp 519 | -------------------------------------------------------------------------------- /videoplayer/res/values-sw360dp/dimen.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 1.00dp 20 | 2.00dp 21 | 3.00dp 22 | 4.00dp 23 | 5.00dp 24 | 6.00dp 25 | 7.00dp 26 | 8.00dp 27 | 9.00dp 28 | 10.00dp 29 | 11.00dp 30 | 12.00dp 31 | 13.00dp 32 | 14.00dp 33 | 15.00dp 34 | 16.00dp 35 | 17.00dp 36 | 18.00dp 37 | 19.00dp 38 | 20.00dp 39 | 21.00dp 40 | 22.00dp 41 | 23.00dp 42 | 24.00dp 43 | 25.00dp 44 | 26.00dp 45 | 27.00dp 46 | 28.00dp 47 | 29.00dp 48 | 30.00dp 49 | 31.00dp 50 | 32.00dp 51 | 33.00dp 52 | 34.00dp 53 | 35.00dp 54 | 36.00dp 55 | 37.00dp 56 | 38.00dp 57 | 39.00dp 58 | 40.00dp 59 | 41.00dp 60 | 42.00dp 61 | 43.00dp 62 | 44.00dp 63 | 45.00dp 64 | 46.00dp 65 | 47.00dp 66 | 48.00dp 67 | 49.00dp 68 | 50.00dp 69 | 51.00dp 70 | 52.00dp 71 | 53.00dp 72 | 54.00dp 73 | 55.00dp 74 | 56.00dp 75 | 57.00dp 76 | 58.00dp 77 | 59.00dp 78 | 60.00dp 79 | 61.00dp 80 | 62.00dp 81 | 63.00dp 82 | 64.00dp 83 | 65.00dp 84 | 66.00dp 85 | 67.00dp 86 | 68.00dp 87 | 69.00dp 88 | 70.00dp 89 | 71.00dp 90 | 72.00dp 91 | 73.00dp 92 | 74.00dp 93 | 75.00dp 94 | 76.00dp 95 | 77.00dp 96 | 78.00dp 97 | 79.00dp 98 | 80.00dp 99 | 81.00dp 100 | 82.00dp 101 | 83.00dp 102 | 84.00dp 103 | 85.00dp 104 | 86.00dp 105 | 87.00dp 106 | 88.00dp 107 | 89.00dp 108 | 90.00dp 109 | 91.00dp 110 | 92.00dp 111 | 93.00dp 112 | 94.00dp 113 | 95.00dp 114 | 96.00dp 115 | 97.00dp 116 | 98.00dp 117 | 99.00dp 118 | 100.00dp 119 | 101.00dp 120 | 102.00dp 121 | 103.00dp 122 | 104.00dp 123 | 105.00dp 124 | 106.00dp 125 | 107.00dp 126 | 108.00dp 127 | 109.00dp 128 | 110.00dp 129 | 111.00dp 130 | 112.00dp 131 | 113.00dp 132 | 114.00dp 133 | 115.00dp 134 | 116.00dp 135 | 117.00dp 136 | 118.00dp 137 | 119.00dp 138 | 120.00dp 139 | 121.00dp 140 | 122.00dp 141 | 123.00dp 142 | 124.00dp 143 | 125.00dp 144 | 126.00dp 145 | 127.00dp 146 | 128.00dp 147 | 129.00dp 148 | 130.00dp 149 | 131.00dp 150 | 132.00dp 151 | 133.00dp 152 | 134.00dp 153 | 135.00dp 154 | 136.00dp 155 | 137.00dp 156 | 138.00dp 157 | 139.00dp 158 | 140.00dp 159 | 141.00dp 160 | 142.00dp 161 | 143.00dp 162 | 144.00dp 163 | 145.00dp 164 | 146.00dp 165 | 147.00dp 166 | 148.00dp 167 | 149.00dp 168 | 150.00dp 169 | 151.00dp 170 | 152.00dp 171 | 153.00dp 172 | 154.00dp 173 | 155.00dp 174 | 156.00dp 175 | 157.00dp 176 | 158.00dp 177 | 159.00dp 178 | 160.00dp 179 | 161.00dp 180 | 162.00dp 181 | 163.00dp 182 | 164.00dp 183 | 165.00dp 184 | 166.00dp 185 | 167.00dp 186 | 168.00dp 187 | 169.00dp 188 | 170.00dp 189 | 171.00dp 190 | 172.00dp 191 | 173.00dp 192 | 174.00dp 193 | 175.00dp 194 | 176.00dp 195 | 177.00dp 196 | 178.00dp 197 | 179.00dp 198 | 180.00dp 199 | 181.00dp 200 | 182.00dp 201 | 183.00dp 202 | 184.00dp 203 | 185.00dp 204 | 186.00dp 205 | 187.00dp 206 | 188.00dp 207 | 189.00dp 208 | 190.00dp 209 | 191.00dp 210 | 192.00dp 211 | 193.00dp 212 | 194.00dp 213 | 195.00dp 214 | 196.00dp 215 | 197.00dp 216 | 198.00dp 217 | 199.00dp 218 | 200.00dp 219 | 201.00dp 220 | 202.00dp 221 | 203.00dp 222 | 204.00dp 223 | 205.00dp 224 | 206.00dp 225 | 207.00dp 226 | 208.00dp 227 | 209.00dp 228 | 210.00dp 229 | 211.00dp 230 | 212.00dp 231 | 213.00dp 232 | 214.00dp 233 | 215.00dp 234 | 216.00dp 235 | 217.00dp 236 | 218.00dp 237 | 219.00dp 238 | 220.00dp 239 | 221.00dp 240 | 222.00dp 241 | 223.00dp 242 | 224.00dp 243 | 225.00dp 244 | 226.00dp 245 | 227.00dp 246 | 228.00dp 247 | 229.00dp 248 | 230.00dp 249 | 231.00dp 250 | 232.00dp 251 | 233.00dp 252 | 234.00dp 253 | 235.00dp 254 | 236.00dp 255 | 237.00dp 256 | 238.00dp 257 | 239.00dp 258 | 240.00dp 259 | 241.00dp 260 | 242.00dp 261 | 243.00dp 262 | 244.00dp 263 | 245.00dp 264 | 246.00dp 265 | 247.00dp 266 | 248.00dp 267 | 249.00dp 268 | 250.00dp 269 | 251.00dp 270 | 252.00dp 271 | 253.00dp 272 | 254.00dp 273 | 255.00dp 274 | 256.00dp 275 | 257.00dp 276 | 258.00dp 277 | 259.00dp 278 | 260.00dp 279 | 261.00dp 280 | 262.00dp 281 | 263.00dp 282 | 264.00dp 283 | 265.00dp 284 | 266.00dp 285 | 267.00dp 286 | 268.00dp 287 | 269.00dp 288 | 270.00dp 289 | 271.00dp 290 | 272.00dp 291 | 273.00dp 292 | 274.00dp 293 | 275.00dp 294 | 276.00dp 295 | 277.00dp 296 | 278.00dp 297 | 279.00dp 298 | 280.00dp 299 | 281.00dp 300 | 282.00dp 301 | 283.00dp 302 | 284.00dp 303 | 285.00dp 304 | 286.00dp 305 | 287.00dp 306 | 288.00dp 307 | 289.00dp 308 | 290.00dp 309 | 291.00dp 310 | 292.00dp 311 | 293.00dp 312 | 294.00dp 313 | 295.00dp 314 | 296.00dp 315 | 297.00dp 316 | 298.00dp 317 | 299.00dp 318 | 300.00dp 319 | 301.00dp 320 | 302.00dp 321 | 303.00dp 322 | 304.00dp 323 | 305.00dp 324 | 306.00dp 325 | 307.00dp 326 | 308.00dp 327 | 309.00dp 328 | 310.00dp 329 | 311.00dp 330 | 312.00dp 331 | 313.00dp 332 | 314.00dp 333 | 315.00dp 334 | 316.00dp 335 | 317.00dp 336 | 318.00dp 337 | 319.00dp 338 | 320.00dp 339 | 321.00dp 340 | 322.00dp 341 | 323.00dp 342 | 324.00dp 343 | 325.00dp 344 | 326.00dp 345 | 327.00dp 346 | 328.00dp 347 | 329.00dp 348 | 330.00dp 349 | 331.00dp 350 | 332.00dp 351 | 333.00dp 352 | 334.00dp 353 | 335.00dp 354 | 336.00dp 355 | 337.00dp 356 | 338.00dp 357 | 339.00dp 358 | 340.00dp 359 | 341.00dp 360 | 342.00dp 361 | 343.00dp 362 | 344.00dp 363 | 345.00dp 364 | 346.00dp 365 | 347.00dp 366 | 348.00dp 367 | 349.00dp 368 | 350.00dp 369 | 351.00dp 370 | 352.00dp 371 | 353.00dp 372 | 354.00dp 373 | 355.00dp 374 | 356.00dp 375 | 357.00dp 376 | 358.00dp 377 | 359.00dp 378 | 360.00dp 379 | 361.00dp 380 | 362.00dp 381 | 363.00dp 382 | 364.00dp 383 | 365.00dp 384 | 366.00dp 385 | 367.00dp 386 | 368.00dp 387 | 369.00dp 388 | 370.00dp 389 | 371.00dp 390 | 372.00dp 391 | 373.00dp 392 | 374.00dp 393 | 375.00dp 394 | 376.00dp 395 | 377.00dp 396 | 378.00dp 397 | 379.00dp 398 | 380.00dp 399 | 381.00dp 400 | 382.00dp 401 | 383.00dp 402 | 384.00dp 403 | 385.00dp 404 | 386.00dp 405 | 387.00dp 406 | 388.00dp 407 | 389.00dp 408 | 390.00dp 409 | 391.00dp 410 | 392.00dp 411 | 393.00dp 412 | 394.00dp 413 | 395.00dp 414 | 396.00dp 415 | 397.00dp 416 | 398.00dp 417 | 399.00dp 418 | 400.00dp 419 | 401.00dp 420 | 402.00dp 421 | 403.00dp 422 | 404.00dp 423 | 405.00dp 424 | 406.00dp 425 | 407.00dp 426 | 408.00dp 427 | 409.00dp 428 | 410.00dp 429 | 411.00dp 430 | 412.00dp 431 | 413.00dp 432 | 414.00dp 433 | 415.00dp 434 | 416.00dp 435 | 417.00dp 436 | 418.00dp 437 | 419.00dp 438 | 420.00dp 439 | 421.00dp 440 | 422.00dp 441 | 423.00dp 442 | 424.00dp 443 | 425.00dp 444 | 426.00dp 445 | 427.00dp 446 | 428.00dp 447 | 429.00dp 448 | 430.00dp 449 | 431.00dp 450 | 432.00dp 451 | 433.00dp 452 | 434.00dp 453 | 435.00dp 454 | 436.00dp 455 | 437.00dp 456 | 438.00dp 457 | 439.00dp 458 | 440.00dp 459 | 441.00dp 460 | 442.00dp 461 | 443.00dp 462 | 444.00dp 463 | 445.00dp 464 | 446.00dp 465 | 447.00dp 466 | 448.00dp 467 | 449.00dp 468 | 450.00dp 469 | 451.00dp 470 | 452.00dp 471 | 453.00dp 472 | 454.00dp 473 | 455.00dp 474 | 456.00dp 475 | 457.00dp 476 | 458.00dp 477 | 459.00dp 478 | 460.00dp 479 | 461.00dp 480 | 462.00dp 481 | 463.00dp 482 | 464.00dp 483 | 465.00dp 484 | 466.00dp 485 | 467.00dp 486 | 468.00dp 487 | 469.00dp 488 | 470.00dp 489 | 471.00dp 490 | 472.00dp 491 | 473.00dp 492 | 474.00dp 493 | 475.00dp 494 | 476.00dp 495 | 477.00dp 496 | 478.00dp 497 | 479.00dp 498 | 480.00dp 499 | 481.00dp 500 | 482.00dp 501 | 483.00dp 502 | 484.00dp 503 | 485.00dp 504 | 486.00dp 505 | 487.00dp 506 | 488.00dp 507 | 489.00dp 508 | 490.00dp 509 | 491.00dp 510 | 492.00dp 511 | 493.00dp 512 | 494.00dp 513 | 495.00dp 514 | 496.00dp 515 | 497.00dp 516 | 498.00dp 517 | 499.00dp 518 | 500.00dp 519 | -------------------------------------------------------------------------------- /videoplayer/res/values/font.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | @dimen/dp_30 20 | @dimen/dp_27 21 | @dimen/dp_24 22 | @dimen/dp_22 23 | @dimen/dp_20 24 | @dimen/dp_18 25 | @dimen/dp_16 26 | @dimen/dp_14 27 | @dimen/dp_12 28 | @dimen/dp_10 29 | @dimen/dp_8 30 | @dimen/dp_6 31 | 32 | @dimen/F_title 33 | @dimen/H_title 34 | 35 | -------------------------------------------------------------------------------- /videoplayer/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | IJKplayerDemo 22 | 23 | N/A 24 | Close 25 | Exit 26 | Sample 27 | Recent 28 | Settings 29 | Tracks 30 | Player 31 | Render 32 | Scale 33 | Info 34 | vdec 35 | fps 36 | v-cache 37 | a-cache 38 | 39 | Media Information 40 | Player 41 | Media 42 | Profile level 43 | Pixel format 44 | Resolution 45 | Length 46 | Stream #%d 47 | Type 48 | Language 49 | Codec 50 | Frame rate 51 | Bit rate 52 | Sample rate 53 | Channels 54 | * 55 | * 56 | 57 | Video 58 | Audio 59 | Subtitle 60 | Timed text 61 | Meta data 62 | Unknown 63 | 64 | 未找到服务器! 65 | 未找到服务器! 66 | 确定 67 | 68 | Aspect / Fit parent 69 | Aspect / Fill parent 70 | Aspect / Wrap content 71 | Free / Fill parent 72 | 16:9 / Fit parent 73 | 4:3 / Fit parent 74 | 75 | Render: None 76 | Render: SurfaceView 77 | Render: TextureView 78 | 79 | Player: None 80 | Player: AndroidMediaPlayer 81 | Player: IjkMediaPlayer 82 | Player: IjkExoMediaPlayer 83 | 84 | 85 | -------------------------------------------------------------------------------- /videoplayer/res/values/strings_pref.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | General 22 | 23 | pref.enable_background_play 24 | Enable background play 25 | need Android 4.0+ 26 | 27 | pref.using_android_player 28 | Using system player 29 | 30 | 31 | pref.player 32 | Choose Player 33 | 34 | Auto Select 35 | AndroidMediaPlayer 36 | IjkMediaPlayer 37 | IjkExoMediaPlayer 38 | 39 | 40 | 0 41 | 1 42 | 2 43 | 3 44 | 45 | 46 | Auto Select 47 | AndroidMediaPlayer 48 | IjkMediaPlayer 49 | IjkExoMediaPlayer 50 | 51 | 52 | 53 | Video: ijkplayer 54 | 55 | pref.using_media_codec 56 | Using MediaCodec 57 | 58 | 59 | pref.using_media_codec_auto_rotate 60 | Using MediaCodec auto rotate 61 | 62 | 63 | pref.pixel_format 64 | Pixel Format 65 | 66 | Auto Select 67 | RGB 565 68 | RGB 888X 69 | YV12 70 | 71 | 72 | 73 | fcc-rv16 74 | fcc-rv32 75 | fcc-yv12 76 | 77 | 78 | Auto Select 79 | RGB 565 80 | RGB 888X 81 | YV12 82 | 83 | 84 | 85 | Audio: ijkplayer 86 | 87 | pref.using_opensl_es 88 | Using OpenSL ES 89 | 90 | 91 | 92 | RenderView 93 | 94 | pref.enable_no_view 95 | Enable NoView 96 | 97 | 98 | pref.enable_surface_view 99 | Enable SurfaceView 100 | 101 | 102 | pref.enable_texture_view 103 | Enable TextureView 104 | 105 | 106 | pref.enable_detached_surface_texture 107 | Enable detached SurfaceTexture 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /videoplayer/src/com/ishow/videoplayer/settings/Settings.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 The yuhaiyang Android Source Project 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @author: y.haiyang@qq.com 17 | */ 18 | 19 | package com.ishow.videoplayer.settings; 20 | 21 | public class Settings { 22 | 23 | /** 24 | * 是否使用 opensles 25 | */ 26 | public static final boolean USING_OPEN_SLES = false; 27 | /** 28 | * 使用硬解还是软解 29 | */ 30 | public static final int MEDIA_CODE = 0; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /videoplayer/src/com/ishow/videoplayer/utils/ScreenOrientationUtils.java: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Copyright (C) 2016 The yuhaiyang Android Source Project 4 | *

5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | *

9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | *

11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | * @author: y.haiyang@qq.com 18 | */ 19 | 20 | package com.ishow.videoplayer.utils; 21 | 22 | import android.app.Activity; 23 | import android.content.Context; 24 | import android.content.pm.ActivityInfo; 25 | import android.content.res.Configuration; 26 | import android.util.Log; 27 | import android.view.WindowManager; 28 | 29 | public class ScreenOrientationUtils { 30 | private static final String TAG = "ScreenOrientationUtils"; 31 | 32 | /** 33 | * 如果 当前activity 是非sensor默认则进行横屏 34 | */ 35 | public static void setLandscape(Context context) { 36 | setLandscape(context, false); 37 | } 38 | 39 | /** 40 | * 如果 当前activity 是非sensor默认则进行横屏 41 | */ 42 | public static void setLandscape(Context context, boolean force) { 43 | if (context == null || !(context instanceof Activity)) { 44 | Log.i(TAG, "setLandscape: context is null or context is not activity"); 45 | return; 46 | } 47 | Activity activity = (Activity) context; 48 | if (activity.getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_SENSOR && !force) { 49 | return; 50 | } 51 | 52 | activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE); 53 | } 54 | 55 | /** 56 | * 如果 当前activity 是非sensor默认则进行竖屏 57 | */ 58 | public static void setPortrait(Context context) { 59 | setPortrait(context, false); 60 | } 61 | 62 | /** 63 | * 如果 当前activity 是非sensor默认则进行竖屏 64 | */ 65 | public static void setPortrait(Context context, boolean force) { 66 | if (context == null || !(context instanceof Activity)) { 67 | Log.i(TAG, "setPortrait: context is null or context is not activity"); 68 | return; 69 | } 70 | Activity activity = (Activity) context; 71 | if (activity.getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_SENSOR && !force) { 72 | return; 73 | } 74 | activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT); 75 | } 76 | 77 | /** 78 | * 如果 当前activity 是非sensor默认则进行竖屏 79 | */ 80 | public static void setSensor(Context context) { 81 | if (context == null || !(context instanceof Activity)) { 82 | Log.i(TAG, "setPortrait: context is null or context is not activity"); 83 | return; 84 | } 85 | Activity activity = (Activity) context; 86 | 87 | activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR); 88 | } 89 | 90 | /** 91 | * 是否是横屏 92 | */ 93 | public static boolean isLandscape(Context context) { 94 | if (context == null) { 95 | Log.i(TAG, "isPortrait: context is null "); 96 | return false; 97 | } 98 | return context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; 99 | } 100 | 101 | /** 102 | * 是否是竖屏 103 | */ 104 | public static boolean isPortrait(Context context) { 105 | if (context == null) { 106 | Log.i(TAG, "isPortrait: context is null "); 107 | return false; 108 | } 109 | return context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; 110 | } 111 | 112 | /** 113 | * 设置状态栏是否可见 114 | */ 115 | public static void setStatusBarVisible(Context context, boolean isVisible) { 116 | if (context == null || !(context instanceof Activity)) { 117 | Log.i(TAG, "setStatusBarVisible: context is null or context is not activity"); 118 | return; 119 | } 120 | Activity activity = (Activity) context; 121 | WindowManager.LayoutParams lp = activity.getWindow().getAttributes(); 122 | if (isVisible) { 123 | lp.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN; 124 | activity.getWindow().setAttributes(lp); 125 | } else { 126 | lp.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN); 127 | activity.getWindow().setAttributes(lp); 128 | activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /videoplayer/src/com/ishow/videoplayer/utils/VideoUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 The yuhaiyang Android Source Project 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @author: y.haiyang@qq.com 17 | */ 18 | 19 | package com.ishow.videoplayer.utils; 20 | 21 | import android.annotation.SuppressLint; 22 | import android.content.Context; 23 | import android.content.pm.PackageInfo; 24 | import android.content.pm.PackageManager; 25 | import android.content.pm.PackageManager.NameNotFoundException; 26 | import android.os.Build; 27 | import android.os.Environment; 28 | import android.os.StatFs; 29 | import android.util.Log; 30 | 31 | import java.io.BufferedReader; 32 | import java.io.IOException; 33 | import java.io.InputStreamReader; 34 | import java.text.SimpleDateFormat; 35 | import java.util.Date; 36 | import java.util.Locale; 37 | 38 | import dalvik.system.PathClassLoader; 39 | 40 | public class VideoUtils { 41 | 42 | public enum eAndroidOS { 43 | UNKNOWN, MIUI, EmotionUI, Flyme, NubiaUI, Nokia_X, ColorOS, HTC, ZTE, FuntouchOS, 44 | } 45 | 46 | public static final String FORMAT_ALL_DATE = "yyyy-MM-dd HH:mm:ss.SSS"; 47 | public static final String FORMAT_TIME = "HH:mm:ss"; 48 | public static final String FORMAT_DATE = "yyyy-MM-dd"; 49 | public static final String FORMAT_SIMPLE_DATE = "yyyyMMdd"; 50 | 51 | private final static SimpleDateFormat sFORMAT = new SimpleDateFormat( 52 | FORMAT_ALL_DATE, Locale.CHINA); 53 | 54 | private static String mSystemProperty = getSystemProperty(); 55 | 56 | private final static String TAG = "VideoUtils"; 57 | 58 | public static String getAppVersion(Context context) { 59 | return ""; 60 | } 61 | 62 | public static String getAppName(Context context) { 63 | return ""; 64 | } 65 | 66 | public static String getDocumentPath(Context context) { 67 | return context.getFilesDir().getAbsolutePath(); 68 | } 69 | 70 | public static String getSDCardDataPath(Context context) { 71 | if (Environment.getExternalStorageState().equals( 72 | Environment.MEDIA_MOUNTED)) { 73 | return Environment.getExternalStorageDirectory().getAbsolutePath(); 74 | } 75 | return null; 76 | } 77 | 78 | @SuppressWarnings("deprecation") 79 | @SuppressLint("NewApi") 80 | public static boolean getSDCardRemainCanWrite(Context context, 81 | long remainSize) { 82 | String path = getSDCardDataPath(context); 83 | StatFs statFS = new StatFs(path); 84 | long blockSize = 0L; 85 | if (getSDKInt() >= 18) { 86 | blockSize = statFS.getBlockCountLong(); 87 | } else { 88 | blockSize = statFS.getBlockSize(); 89 | } 90 | long availableBlock = 0L; 91 | if (getSDKInt() >= 18) { 92 | availableBlock = statFS.getAvailableBlocksLong(); 93 | } else { 94 | availableBlock = statFS.getAvailableBlocks(); 95 | } 96 | long size = blockSize * availableBlock; 97 | if (size > remainSize) { 98 | return true; 99 | } 100 | 101 | return false; 102 | } 103 | 104 | public static String getSDKVersion(Context context) { 105 | PackageManager pm = context.getPackageManager(); 106 | String pkgName = context.getPackageName(); 107 | PackageInfo pkgInfo = null; 108 | String ret = ""; 109 | try { 110 | pkgInfo = pm.getPackageInfo(pkgName, 111 | PackageManager.GET_CONFIGURATIONS); 112 | ret = pkgInfo.versionName; 113 | } catch (NameNotFoundException ex) { 114 | 115 | } 116 | return ret; 117 | } 118 | 119 | public static String generatePlayTime(long time) { 120 | if (time % 1000 >= 500) { 121 | time += 1000; 122 | } 123 | int totalSeconds = (int) (time / 1000); 124 | int seconds = totalSeconds % 60; 125 | int minutes = (totalSeconds / 60) % 60; 126 | int hours = totalSeconds / 3600; 127 | 128 | return hours > 0 ? 129 | String.format(Locale.CHINA, "%02d:%02d:%02d", hours, minutes, seconds) 130 | : 131 | String.format(Locale.CHINA, "%02d:%02d", minutes, seconds); 132 | } 133 | 134 | /** 135 | * 用反射方式加载类 136 | * 137 | * @param context 138 | * @param path 139 | * @return 140 | */ 141 | public static Object loadClass(Context context, String path) { 142 | try { 143 | String dexPath = context.getApplicationInfo().sourceDir; 144 | PathClassLoader pathClassLoader = new PathClassLoader(dexPath, 145 | context.getClassLoader()); 146 | Class c = Class.forName(path, true, pathClassLoader); 147 | Object ret = c.newInstance(); 148 | return ret; 149 | } catch (InstantiationException ex1) { 150 | ex1.printStackTrace(); 151 | } catch (IllegalAccessException ex2) { 152 | ex2.printStackTrace(); 153 | } catch (ClassNotFoundException ex3) { 154 | ex3.printStackTrace(); 155 | } 156 | 157 | return null; 158 | } 159 | 160 | public static String generateTime(long time, boolean isLong) { 161 | Date date = new Date(time); 162 | sFORMAT.applyPattern(isLong ? FORMAT_ALL_DATE : FORMAT_TIME); 163 | String LgTime = null; 164 | try { 165 | LgTime = sFORMAT.format(date); 166 | } catch (Exception e) { 167 | try { 168 | SimpleDateFormat format = new SimpleDateFormat( 169 | isLong ? FORMAT_ALL_DATE : FORMAT_TIME, Locale.CHINA); 170 | LgTime = format.format(new Date()); 171 | e.printStackTrace(); 172 | } catch (Exception e1) { 173 | e1.printStackTrace(); 174 | LgTime = ""; 175 | } 176 | } 177 | return LgTime; 178 | } 179 | 180 | public static String getOSVersionInfo() { 181 | return Build.VERSION.RELEASE; 182 | } 183 | 184 | /** 185 | * Get mobile model, like GT-i9500 etc. 186 | * 187 | * @return 188 | */ 189 | public static String getMobileModel() { 190 | return Build.MODEL; 191 | } 192 | 193 | public static String getSystemProperty(String propName) { 194 | String line = ""; 195 | BufferedReader input = null; 196 | try { 197 | Process p = Runtime.getRuntime().exec("getprop " + propName); 198 | input = new BufferedReader( 199 | new InputStreamReader(p.getInputStream()), 1024); 200 | line = input.readLine(); 201 | input.close(); 202 | } catch (IOException ex) { 203 | Log.e(TAG, "Unable to read sysprop " + propName, ex); 204 | return null; 205 | } finally { 206 | if (input != null) { 207 | try { 208 | input.close(); 209 | } catch (IOException e) { 210 | Log.e(TAG, "Exception while closing InputStream", e); 211 | } 212 | } 213 | } 214 | return line; 215 | } 216 | 217 | private static String getSystemProperty() { 218 | String line = ""; 219 | BufferedReader input = null; 220 | try { 221 | Process p = Runtime.getRuntime().exec("getprop"); 222 | input = new BufferedReader( 223 | new InputStreamReader(p.getInputStream()), 2048); 224 | String ret = input.readLine(); 225 | while (ret != null) { 226 | line += ret + "\n"; 227 | ret = input.readLine(); 228 | } 229 | input.close(); 230 | } catch (IOException ex) { 231 | Log.e(TAG, "Unable to read sysprop", ex); 232 | return null; 233 | } finally { 234 | if (input != null) { 235 | try { 236 | input.close(); 237 | } catch (IOException e) { 238 | Log.e(TAG, "Exception while closing InputStream", e); 239 | } 240 | } 241 | } 242 | return line; 243 | } 244 | 245 | public static eAndroidOS filterOS() { 246 | String prop = mSystemProperty; 247 | if (prop.contains("miui")) { 248 | return eAndroidOS.MIUI; 249 | } else if (prop.contains("EmotionUI")) { 250 | return eAndroidOS.EmotionUI; 251 | } else if (prop.contains("flyme")) { 252 | return eAndroidOS.Flyme; 253 | } else if (prop.contains("[ro.build.user]: [nubia]")) { 254 | return eAndroidOS.NubiaUI; 255 | } else if (prop.contains("Nokia_X")) { 256 | return eAndroidOS.Nokia_X; 257 | } else if (prop.contains("[ro.build.soft.version]: [A.")) { 258 | return eAndroidOS.ColorOS; 259 | } else if (prop.contains("ro.htc.")) { 260 | return eAndroidOS.HTC; 261 | } else if (prop.contains("[ro.build.user]: [zte")) { 262 | return eAndroidOS.ZTE; 263 | } else if (prop.contains("[ro.product.brand]: [vivo")) { 264 | return eAndroidOS.FuntouchOS; 265 | } 266 | return eAndroidOS.UNKNOWN; 267 | } 268 | 269 | public static String getBrand() { 270 | return Build.BRAND; 271 | } 272 | 273 | public static String getModel() { 274 | return Build.MODEL; 275 | } 276 | 277 | public static String getSDKRelease() { 278 | return Build.VERSION.RELEASE; 279 | } 280 | 281 | public static int getSDKInt() { 282 | return Build.VERSION.SDK_INT; 283 | } 284 | 285 | public static eAndroidOS getOS() { 286 | return filterOS(); 287 | } 288 | } 289 | -------------------------------------------------------------------------------- /videoplayer/src/com/ishow/videoplayer/widget/MediaController.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 The yuhaiyang Android Source Project 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @author: y.haiyang@qq.com 17 | */ 18 | 19 | package com.ishow.videoplayer.widget; 20 | 21 | import android.annotation.SuppressLint; 22 | import android.app.Activity; 23 | import android.content.Context; 24 | import android.database.ContentObserver; 25 | import android.net.Uri; 26 | import android.os.Handler; 27 | import android.os.Message; 28 | import android.provider.Settings; 29 | import android.util.AttributeSet; 30 | import android.util.Log; 31 | import android.view.LayoutInflater; 32 | import android.view.View; 33 | import android.view.ViewGroup; 34 | import android.view.ViewParent; 35 | import android.widget.FrameLayout; 36 | import android.widget.ImageView; 37 | import android.widget.MediaController.MediaPlayerControl; 38 | import android.widget.RelativeLayout; 39 | import android.widget.SeekBar; 40 | import android.widget.TextView; 41 | 42 | import com.ishow.videoplayer.R; 43 | import com.ishow.videoplayer.utils.ScreenOrientationUtils; 44 | import com.ishow.videoplayer.utils.VideoUtils; 45 | import com.ishow.videoplayer.widget.media.IMediaController; 46 | import com.ishow.videoplayer.widget.media.VideoView; 47 | 48 | import tv.danmaku.ijk.media.player.IMediaPlayer; 49 | 50 | 51 | public class MediaController extends FrameLayout implements IMediaController, View.OnClickListener { 52 | private static final String TAG = "MediaController"; 53 | 54 | /** 55 | * 更新进度条 56 | */ 57 | private static final int HANDLER_UPDATE_PROGRESS = 1003; 58 | /** 59 | * 设置Activity位sensor控制 60 | */ 61 | private static final int HANDLER_SCREEN_SENSOR = 1004; 62 | /** 63 | * 隐藏 64 | */ 65 | private static final int HANDLER_HIDE_NAVIGATION = 1005; 66 | /** 67 | * 多长时间后重新设置为sensor控制 68 | */ 69 | private static final int DEFAULT_DELAY_TIME_SET_SENSOR = 5000; 70 | private boolean mDragging; 71 | 72 | private VideoView mVideoView; 73 | /** 74 | * 普通功能的包裹区域 75 | */ 76 | private View mNormalFeaturesContent; 77 | // Top panel 中包裹的 78 | private TextView mTitle; 79 | // 进度条 80 | private SeekBar mProgress; 81 | // 当前时间和总共多长时间 82 | private TextView mCurrentTime, mEndTime; 83 | 84 | private ImageView mFullScreenView; 85 | private ImageView mStartOrPauseView; 86 | private View mPlayNextView; 87 | /** 88 | * 加载功能的包裹区域 89 | */ 90 | private View mLoadingContent; 91 | /** 92 | * 滑动功能区 93 | */ 94 | private View mSlideContent; 95 | private ImageView mSlideIcon; 96 | private TextView mSlideTargetTime; 97 | private TextView mSlideTotleTime; 98 | /** 99 | * 广告区 100 | */ 101 | private RelativeLayout mADContent; 102 | 103 | private ViewGroup mPortraitVideoRootView; 104 | private ViewGroup mLandVideoRootView; 105 | private MediaPlayerControl mPlayer; 106 | 107 | private CallBack mCallBack; 108 | 109 | private Handler mHandler = new Handler() { 110 | @Override 111 | public void handleMessage(Message msg) { 112 | super.handleMessage(msg); 113 | switch (msg.what) { 114 | case HANDLER_UPDATE_PROGRESS: 115 | int pos = setProgress(); 116 | Log.i(TAG, "isPlaying = " + mPlayer.isPlaying()); 117 | if (mPlayer.isPlaying()) { 118 | msg = obtainMessage(HANDLER_UPDATE_PROGRESS); 119 | sendMessageDelayed(msg, 1000 - (pos % 1000)); 120 | } 121 | 122 | break; 123 | case HANDLER_SCREEN_SENSOR: 124 | Log.i(TAG, "handleMessage: HANDLER_SCREEN_SENSOR = " + isCanAutoRotation()); 125 | if (isCanAutoRotation()) { 126 | ScreenOrientationUtils.setSensor(getContext()); 127 | } else if (ScreenOrientationUtils.isLandscape(getContext())) { 128 | ScreenOrientationUtils.setLandscape(getContext(), true); 129 | } else { 130 | ScreenOrientationUtils.setPortrait(getContext(), true); 131 | } 132 | break; 133 | case HANDLER_HIDE_NAVIGATION: 134 | if (ScreenOrientationUtils.isLandscape(getContext())) { 135 | hideSystemBar(); 136 | } 137 | break; 138 | } 139 | } 140 | }; 141 | 142 | public MediaController(Context context) { 143 | this(context, null); 144 | } 145 | 146 | public MediaController(Context context, AttributeSet attrs) { 147 | this(context, attrs, 0); 148 | } 149 | 150 | public MediaController(Context context, AttributeSet attrs, int defStyleAttr) { 151 | super(context, attrs, defStyleAttr); 152 | init(); 153 | } 154 | 155 | private void init() { 156 | LayoutInflater layoutInflater = LayoutInflater.from(getContext()); 157 | layoutInflater.inflate(R.layout.media_controller, this, true); 158 | 159 | mNormalFeaturesContent = findViewById(R.id.normal_content); 160 | ImageView back = (ImageView) findViewById(R.id.back); 161 | back.setOnClickListener(this); 162 | mTitle = (TextView) findViewById(R.id.title); 163 | 164 | mFullScreenView = (ImageView) findViewById(R.id.full_screen); 165 | mFullScreenView.setOnClickListener(this); 166 | 167 | mStartOrPauseView = (ImageView) findViewById(R.id.start_or_pause); 168 | mStartOrPauseView.setOnClickListener(this); 169 | 170 | mPlayNextView = findViewById(R.id.play_next); 171 | mPlayNextView.setOnClickListener(this); 172 | 173 | mProgress = (SeekBar) findViewById(R.id.progress); 174 | mProgress.setOnSeekBarChangeListener(mSeekListener); 175 | mProgress.setMax(1000); 176 | 177 | mCurrentTime = (TextView) findViewById(R.id.current_time); 178 | mEndTime = (TextView) findViewById(R.id.end_time); 179 | 180 | // Loading 区域 181 | mLoadingContent = findViewById(R.id.loading_content); 182 | 183 | mSlideContent = findViewById(R.id.slide_content); 184 | mSlideIcon = (ImageView) findViewById(R.id.slide_icon); 185 | mSlideTargetTime = (TextView) findViewById(R.id.slide_time_target); 186 | mSlideTotleTime = (TextView) findViewById(R.id.slide_time_totle); 187 | 188 | mADContent = (RelativeLayout) findViewById(R.id.ad_content); 189 | } 190 | 191 | @Override 192 | public void hide() { 193 | Log.i(TAG, "timeout hide"); 194 | mNormalFeaturesContent.setVisibility(GONE); 195 | mHandler.removeMessages(HANDLER_UPDATE_PROGRESS); 196 | 197 | mHandler.removeMessages(HANDLER_HIDE_NAVIGATION); 198 | mHandler.sendEmptyMessage(HANDLER_HIDE_NAVIGATION); 199 | } 200 | 201 | @Override 202 | public void show() { 203 | Log.i(TAG, "show"); 204 | /** 205 | * 1. 先进性设置播放状态 206 | * 2. 更新进度条 207 | * 3. 显示 208 | */ 209 | showSystemBar(); 210 | mHandler.sendEmptyMessage(HANDLER_UPDATE_PROGRESS); 211 | syncPlayStatus(); 212 | mNormalFeaturesContent.setVisibility(VISIBLE); 213 | } 214 | 215 | @Override 216 | public boolean isShowing() { 217 | return mNormalFeaturesContent.getVisibility() == View.VISIBLE; 218 | } 219 | 220 | @Override 221 | public void showLoading() { 222 | if (mLoadingContent.getVisibility() == VISIBLE) { 223 | return; 224 | } 225 | mLoadingContent.setVisibility(VISIBLE); 226 | } 227 | 228 | @Override 229 | public void hideLoading() { 230 | mLoadingContent.setVisibility(GONE); 231 | } 232 | 233 | @Override 234 | public void showSlideView(long position, float distance) { 235 | mSlideContent.setVisibility(VISIBLE); 236 | int duration = mPlayer.getDuration(); 237 | 238 | if (distance > 0) { 239 | mSlideIcon.setImageResource(R.drawable.ic_forward); 240 | } else { 241 | mSlideIcon.setImageResource(R.drawable.ic_backward); 242 | } 243 | 244 | mSlideTargetTime.setText(VideoUtils.generatePlayTime(position)); 245 | mSlideTotleTime.setText(VideoUtils.generatePlayTime(duration)); 246 | } 247 | 248 | @Override 249 | public void hideSlideView() { 250 | mSlideContent.setVisibility(GONE); 251 | } 252 | 253 | @Override 254 | public void effectiveSlide(long position) { 255 | mPlayer.seekTo((int) (position)); 256 | } 257 | 258 | @Override 259 | public RelativeLayout getAdView() { 260 | return mADContent; 261 | } 262 | 263 | @Override 264 | public void setAnchorView(View view) { 265 | if (view == null) { 266 | return; 267 | } 268 | // 如果已经设置了 那么就直接退出就好 269 | if (mVideoView != null) { 270 | return; 271 | } 272 | 273 | // 如果有父类 那么先移除 274 | ViewParent parent = getParent(); 275 | if (parent != null) { 276 | ((ViewGroup) parent).removeView(this); 277 | } 278 | 279 | mVideoView = (VideoView) view; 280 | mVideoView.addView(this); 281 | mVideoView.bringChildToFront(this); 282 | mVideoView.setOnCompletionListener(mCompletionListener); 283 | 284 | mPortraitVideoRootView = (ViewGroup) mVideoView.getParent(); 285 | 286 | mHandler.sendEmptyMessage(HANDLER_SCREEN_SENSOR); 287 | registerContentObservers(); 288 | } 289 | 290 | /** 291 | * 设置横屏时候的RootView 292 | */ 293 | public void setLandVideoRootView(ViewGroup root) { 294 | mLandVideoRootView = root; 295 | } 296 | 297 | @Override 298 | public void setMediaPlayer(android.widget.MediaController.MediaPlayerControl player) { 299 | mPlayer = player; 300 | } 301 | 302 | public void setTitle(String title) { 303 | mTitle.setText(title); 304 | } 305 | 306 | 307 | public void setPlayNextVisibility(int visiablilty) { 308 | mPlayNextView.setVisibility(visiablilty); 309 | } 310 | 311 | 312 | @Override 313 | public void onClick(View v) { 314 | int id = v.getId(); 315 | if (id == R.id.full_screen) { 316 | if (ScreenOrientationUtils.isLandscape(getContext())) { 317 | changePortrait(false); 318 | } else { 319 | changeLand(false); 320 | } 321 | } else if (id == R.id.start_or_pause) { 322 | 323 | if (mCallBack != null) { 324 | mCallBack.onPlay(!mPlayer.isPlaying()); 325 | } 326 | 327 | if (mPlayer.isPlaying()) { 328 | mStartOrPauseView.setImageResource(R.drawable.ic_play_play); 329 | mPlayer.pause(); 330 | } else { 331 | mStartOrPauseView.setImageResource(R.drawable.ic_play_pause); 332 | mPlayer.start(); 333 | mHandler.sendEmptyMessageDelayed(HANDLER_UPDATE_PROGRESS, 1000); 334 | } 335 | } else if (id == R.id.play_next) { 336 | if (mCallBack != null) { 337 | mCallBack.onPlayNext(); 338 | } 339 | } else if (id == R.id.back) { 340 | if (ScreenOrientationUtils.isLandscape(getContext())) { 341 | changePortrait(false); 342 | } else { 343 | Activity activity = (Activity) getContext(); 344 | activity.finish(); 345 | } 346 | } 347 | } 348 | 349 | 350 | /** 351 | * 切换成横屏模式 352 | * 353 | * @param bySensor 是否是通过sensor来切换的 354 | */ 355 | public void changeLand(boolean bySensor) { 356 | 357 | Activity activity = (Activity) getContext(); 358 | mPortraitVideoRootView.removeView(mVideoView); 359 | mFullScreenView.setImageResource(R.drawable.ic_to_smallscreen); 360 | ViewGroup root; 361 | if (mLandVideoRootView != null) { 362 | root = mLandVideoRootView; 363 | } else { 364 | root = (ViewGroup) activity.findViewById(android.R.id.content); 365 | } 366 | if (root != null) { 367 | try { 368 | // 如果是通过sensor来切换的那么非强制更换 369 | ScreenOrientationUtils.setLandscape(activity, !bySensor); 370 | ScreenOrientationUtils.setStatusBarVisible(activity, true); 371 | mHandler.removeMessages(HANDLER_SCREEN_SENSOR); 372 | mHandler.sendEmptyMessageDelayed(HANDLER_SCREEN_SENSOR, DEFAULT_DELAY_TIME_SET_SENSOR); 373 | ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams( 374 | ViewGroup.LayoutParams.MATCH_PARENT, 375 | ViewGroup.LayoutParams.MATCH_PARENT); 376 | root.addView(mVideoView, lp); 377 | 378 | } catch (Exception ex) { 379 | ex.printStackTrace(); 380 | } 381 | } 382 | mHandler.removeMessages(HANDLER_HIDE_NAVIGATION); 383 | mHandler.sendEmptyMessage(HANDLER_HIDE_NAVIGATION); 384 | } 385 | 386 | /** 387 | * 切换成竖屏模式 388 | * 389 | * @param bySensor 是否是通过sensor来切换的 390 | */ 391 | public void changePortrait(boolean bySensor) { 392 | Activity activity = (Activity) getContext(); 393 | ViewGroup root; 394 | if (mLandVideoRootView != null) { 395 | root = mLandVideoRootView; 396 | } else { 397 | root = (ViewGroup) activity.findViewById(android.R.id.content); 398 | } 399 | root.removeView(mVideoView); 400 | mFullScreenView.setImageResource(R.drawable.ic_to_fullscreen); 401 | try { 402 | ScreenOrientationUtils.setPortrait(activity, !bySensor); 403 | ScreenOrientationUtils.setStatusBarVisible(activity, false); 404 | mHandler.removeMessages(HANDLER_SCREEN_SENSOR); 405 | mHandler.sendEmptyMessageDelayed(HANDLER_SCREEN_SENSOR, DEFAULT_DELAY_TIME_SET_SENSOR); 406 | ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams( 407 | ViewGroup.LayoutParams.MATCH_PARENT, 408 | ViewGroup.LayoutParams.MATCH_PARENT); 409 | mPortraitVideoRootView.addView(mVideoView, lp); 410 | } catch (Exception ex) { 411 | ex.printStackTrace(); 412 | } 413 | 414 | showSystemBar(); 415 | } 416 | 417 | /** 418 | * 同步播放状态 419 | */ 420 | private void syncPlayStatus() { 421 | if (mPlayer.isPlaying()) { 422 | mStartOrPauseView.setImageResource(R.drawable.ic_play_pause); 423 | } else { 424 | mStartOrPauseView.setImageResource(R.drawable.ic_play_play); 425 | } 426 | } 427 | 428 | /** 429 | * 设置进度 430 | */ 431 | private int setProgress() { 432 | if (mPlayer == null || mDragging) { 433 | return 0; 434 | } 435 | int position = mPlayer.getCurrentPosition(); 436 | int duration = mPlayer.getDuration(); 437 | if (mNormalFeaturesContent == null) { 438 | return position; 439 | } 440 | 441 | if (duration > 0) { 442 | // use long to avoid overflow 443 | long pos = 1000L * position / duration; 444 | mProgress.setProgress((int) pos); 445 | } 446 | int percent = mPlayer.getBufferPercentage(); 447 | mProgress.setSecondaryProgress(percent * 10); 448 | 449 | mEndTime.setText(VideoUtils.generatePlayTime(duration)); 450 | mCurrentTime.setText(VideoUtils.generatePlayTime(position)); 451 | return position; 452 | } 453 | 454 | /** 455 | * 设置进度 456 | */ 457 | public void setProgress(int position) { 458 | if (position < 0) { 459 | return; 460 | } 461 | mPlayer.seekTo(position); 462 | } 463 | 464 | // There are two scenarios that can trigger the seekbar listener to trigger: 465 | // 466 | // The first is the user using the touchpad to adjust the posititon of the 467 | // seekbar's thumb. In this case onStartTrackingTouch is called followed by 468 | // a number of onProgressChanged notifications, concluded by onStopTrackingTouch. 469 | // We're setting the field "mDragging" to true for the duration of the dragging 470 | // session to avoid jumps in the position in case of ongoing playback. 471 | // 472 | // The second scenario involves the user operating the scroll ball, in this 473 | // case there WON'T BE onStartTrackingTouch/onStopTrackingTouch notifications, 474 | // we will simply apply the updated position without suspending regular updates. 475 | private final SeekBar.OnSeekBarChangeListener mSeekListener = new SeekBar.OnSeekBarChangeListener() { 476 | @Override 477 | public void onStartTrackingTouch(SeekBar bar) { 478 | mDragging = true; 479 | 480 | // By removing these pending progress messages we make sure 481 | // that a) we won't update the progress while the user adjusts 482 | // the seekbar and b) once the user is done dragging the thumb 483 | // we will post one of these messages to the queue again and 484 | // this ensures that there will be exactly one message queued up. 485 | mHandler.removeMessages(HANDLER_UPDATE_PROGRESS); 486 | mVideoView.removeHideAction(); 487 | } 488 | 489 | @Override 490 | public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) { 491 | 492 | if (!fromuser) { 493 | // We're not interested in programmatically generated changes to 494 | // the progress bar's position. 495 | return; 496 | } 497 | 498 | long duration = mPlayer.getDuration(); 499 | long newposition = (duration * progress) / 1000L; 500 | 501 | if (mCurrentTime != null) { 502 | mCurrentTime.setText(VideoUtils.generatePlayTime(newposition)); 503 | } 504 | } 505 | 506 | @Override 507 | public void onStopTrackingTouch(SeekBar bar) { 508 | mDragging = false; 509 | 510 | long duration = mPlayer.getDuration(); 511 | long newposition = (duration * bar.getProgress()) / 1000L; 512 | mPlayer.seekTo((int) newposition); 513 | 514 | mVideoView.setShowAction(); 515 | } 516 | }; 517 | 518 | 519 | private IMediaPlayer.OnCompletionListener mCompletionListener = new IMediaPlayer.OnCompletionListener() { 520 | public void onCompletion(IMediaPlayer mp) { 521 | if (mCallBack != null) { 522 | mCallBack.onComplete(); 523 | } 524 | } 525 | }; 526 | 527 | 528 | private void hideSystemBar() { 529 | // Schedule a runnable to remove the status and navigation bar after a delay 530 | mHandler.postDelayed(mHideSystemBarRunnable, 300); 531 | } 532 | 533 | private final Runnable mHideSystemBarRunnable = new Runnable() { 534 | @SuppressLint("InlinedApi") 535 | @Override 536 | public void run() { 537 | // Delayed removal of status and navigation bar 538 | 539 | // Note that some of these constants are new as of API 16 (Jelly Bean) 540 | // and API 19 (KitKat). It is safe to use them, as they are inlined 541 | // at compile-time and do nothing on earlier devices. 542 | setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE 543 | | View.SYSTEM_UI_FLAG_FULLSCREEN 544 | | View.SYSTEM_UI_FLAG_LAYOUT_STABLE 545 | | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY 546 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 547 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); 548 | } 549 | }; 550 | 551 | @SuppressLint("InlinedApi") 552 | private void showSystemBar() { 553 | // Show the system bar 554 | //setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); 555 | setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); 556 | 557 | // Schedule a runnable to display UI elements after a delay 558 | mHandler.removeCallbacks(mHideSystemBarRunnable); 559 | } 560 | 561 | 562 | public void setCallBack(CallBack callBack) { 563 | mCallBack = callBack; 564 | } 565 | 566 | 567 | public interface CallBack { 568 | void onPlay(boolean isPlaying); 569 | 570 | void onComplete(); 571 | 572 | void onPlayNext(); 573 | } 574 | 575 | 576 | private void registerContentObservers() { 577 | // 通过调用getUriFor 578 | Uri airplaneUri = Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION); 579 | // 注册内容观察者 580 | // 第二个参数false 为精确匹配 581 | getContext().getContentResolver().registerContentObserver(airplaneUri, false, mObserver); 582 | } 583 | 584 | 585 | private void unregisterContentObservers() { 586 | getContext().getContentResolver().unregisterContentObserver(mObserver); 587 | } 588 | 589 | @Override 590 | protected void onAttachedToWindow() { 591 | super.onAttachedToWindow(); 592 | Log.i(TAG, "onAttachedToWindow: mVideoView = " + mVideoView); 593 | if (mVideoView != null) { 594 | registerContentObservers(); 595 | mHandler.sendEmptyMessage(HANDLER_SCREEN_SENSOR); 596 | } 597 | } 598 | 599 | @Override 600 | protected void onDetachedFromWindow() { 601 | super.onDetachedFromWindow(); 602 | Log.i(TAG, "onDetachedFromWindow: "); 603 | unregisterContentObservers(); 604 | } 605 | 606 | 607 | private ContentObserver mObserver = new ContentObserver(null) { 608 | @Override 609 | public void onChange(boolean selfChange) { 610 | super.onChange(selfChange); 611 | mHandler.sendEmptyMessage(HANDLER_SCREEN_SENSOR); 612 | } 613 | }; 614 | 615 | private boolean isCanAutoRotation() { 616 | int acc = Settings.System.getInt(getContext().getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0); 617 | return acc == 1; 618 | } 619 | } 620 | -------------------------------------------------------------------------------- /videoplayer/src/com/ishow/videoplayer/widget/media/IMediaController.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 The yuhaiyang Android Source Project 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @author: y.haiyang@qq.com 17 | */ 18 | 19 | package com.ishow.videoplayer.widget.media; 20 | 21 | import android.view.View; 22 | import android.widget.MediaController; 23 | import android.widget.RelativeLayout; 24 | 25 | public interface IMediaController { 26 | /** 27 | * 显示普通功能区 28 | */ 29 | void hide(); 30 | 31 | /** 32 | * 隐藏普通功能区 33 | */ 34 | void show(); 35 | 36 | /** 37 | * 普通功能区是否显示 38 | */ 39 | boolean isShowing(); 40 | 41 | /** 42 | * 显示Loading 43 | */ 44 | void showLoading(); 45 | 46 | /** 47 | * 隐藏loading 48 | */ 49 | void hideLoading(); 50 | 51 | /** 52 | * 显示滑动的View 53 | */ 54 | void showSlideView(long position, float distance); 55 | 56 | /** 57 | * 隐藏滑动的View 58 | */ 59 | void hideSlideView(); 60 | 61 | /** 62 | * 生效距离 63 | */ 64 | void effectiveSlide(long position); 65 | 66 | /** 67 | * 获取广告View 68 | */ 69 | RelativeLayout getAdView(); 70 | 71 | void setAnchorView(View view); 72 | 73 | void setEnabled(boolean enabled); 74 | 75 | void setMediaPlayer(MediaController.MediaPlayerControl player); 76 | 77 | 78 | } 79 | -------------------------------------------------------------------------------- /videoplayer/src/com/ishow/videoplayer/widget/media/IRenderView.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 The yuhaiyang Android Source Project 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @author: y.haiyang@qq.com 17 | */ 18 | 19 | package com.ishow.videoplayer.widget.media; 20 | 21 | import android.graphics.SurfaceTexture; 22 | import android.support.annotation.NonNull; 23 | import android.support.annotation.Nullable; 24 | import android.view.Surface; 25 | import android.view.SurfaceHolder; 26 | import android.view.View; 27 | 28 | import tv.danmaku.ijk.media.player.IMediaPlayer; 29 | 30 | public interface IRenderView { 31 | int AR_ASPECT_FIT_PARENT = 0; // without clip 32 | int AR_ASPECT_FILL_PARENT = 1; // may clip 33 | int AR_ASPECT_WRAP_CONTENT = 2; 34 | int AR_MATCH_PARENT = 3; 35 | int AR_16_9_FIT_PARENT = 4; 36 | int AR_4_3_FIT_PARENT = 5; 37 | 38 | View getView(); 39 | 40 | boolean shouldWaitForResize(); 41 | 42 | void setVideoSize(int videoWidth, int videoHeight); 43 | 44 | void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen); 45 | 46 | void setVideoRotation(int degree); 47 | 48 | void setAspectRatio(int aspectRatio); 49 | 50 | void addRenderCallback(@NonNull IRenderCallback callback); 51 | 52 | void removeRenderCallback(@NonNull IRenderCallback callback); 53 | 54 | interface ISurfaceHolder { 55 | void bindToMediaPlayer(IMediaPlayer mp); 56 | 57 | @NonNull 58 | IRenderView getRenderView(); 59 | 60 | @Nullable 61 | SurfaceHolder getSurfaceHolder(); 62 | 63 | @Nullable 64 | Surface openSurface(); 65 | 66 | @Nullable 67 | SurfaceTexture getSurfaceTexture(); 68 | } 69 | 70 | interface IRenderCallback { 71 | /** 72 | * @param holder 73 | * @param width could be 0 74 | * @param height could be 0 75 | */ 76 | void onSurfaceCreated(@NonNull ISurfaceHolder holder, int width, int height); 77 | 78 | /** 79 | * @param holder 80 | * @param format could be 0 81 | * @param width 82 | * @param height 83 | */ 84 | void onSurfaceChanged(@NonNull ISurfaceHolder holder, int format, int width, int height); 85 | 86 | void onSurfaceDestroyed(@NonNull ISurfaceHolder holder); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /videoplayer/src/com/ishow/videoplayer/widget/media/MeasureHelper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 The yuhaiyang Android Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @author: y.haiyang@qq.com 17 | */ 18 | 19 | package com.ishow.videoplayer.widget.media; 20 | 21 | import android.content.Context; 22 | import android.support.annotation.NonNull; 23 | import android.view.View; 24 | 25 | import com.ishow.videoplayer.R; 26 | 27 | import java.lang.ref.WeakReference; 28 | 29 | public final class MeasureHelper { 30 | private WeakReference mWeakView; 31 | 32 | private int mVideoWidth; 33 | private int mVideoHeight; 34 | private int mVideoSarNum; 35 | private int mVideoSarDen; 36 | 37 | private int mVideoRotationDegree; 38 | 39 | private int mMeasuredWidth; 40 | private int mMeasuredHeight; 41 | 42 | private int mCurrentAspectRatio = IRenderView.AR_ASPECT_FIT_PARENT; 43 | 44 | public MeasureHelper(View view) { 45 | mWeakView = new WeakReference(view); 46 | } 47 | 48 | public View getView() { 49 | if (mWeakView == null) 50 | return null; 51 | return mWeakView.get(); 52 | } 53 | 54 | public void setVideoSize(int videoWidth, int videoHeight) { 55 | mVideoWidth = videoWidth; 56 | mVideoHeight = videoHeight; 57 | } 58 | 59 | public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) { 60 | mVideoSarNum = videoSarNum; 61 | mVideoSarDen = videoSarDen; 62 | } 63 | 64 | public void setVideoRotation(int videoRotationDegree) { 65 | mVideoRotationDegree = videoRotationDegree; 66 | } 67 | 68 | /** 69 | * Must be called by View.onMeasure(int, int) 70 | * 71 | * @param widthMeasureSpec 72 | * @param heightMeasureSpec 73 | */ 74 | public void doMeasure(int widthMeasureSpec, int heightMeasureSpec) { 75 | //Log.i("@@@@", "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", " 76 | // + MeasureSpec.toString(heightMeasureSpec) + ")"); 77 | if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) { 78 | int tempSpec = widthMeasureSpec; 79 | widthMeasureSpec = heightMeasureSpec; 80 | heightMeasureSpec = tempSpec; 81 | } 82 | 83 | int width = View.getDefaultSize(mVideoWidth, widthMeasureSpec); 84 | int height = View.getDefaultSize(mVideoHeight, heightMeasureSpec); 85 | if (mCurrentAspectRatio == IRenderView.AR_MATCH_PARENT) { 86 | width = widthMeasureSpec; 87 | height = heightMeasureSpec; 88 | } else if (mVideoWidth > 0 && mVideoHeight > 0) { 89 | int widthSpecMode = View.MeasureSpec.getMode(widthMeasureSpec); 90 | int widthSpecSize = View.MeasureSpec.getSize(widthMeasureSpec); 91 | int heightSpecMode = View.MeasureSpec.getMode(heightMeasureSpec); 92 | int heightSpecSize = View.MeasureSpec.getSize(heightMeasureSpec); 93 | 94 | if (widthSpecMode == View.MeasureSpec.AT_MOST && heightSpecMode == View.MeasureSpec.AT_MOST) { 95 | float specAspectRatio = (float) widthSpecSize / (float) heightSpecSize; 96 | float displayAspectRatio; 97 | switch (mCurrentAspectRatio) { 98 | case IRenderView.AR_16_9_FIT_PARENT: 99 | displayAspectRatio = 16.0f / 9.0f; 100 | if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) 101 | displayAspectRatio = 1.0f / displayAspectRatio; 102 | break; 103 | case IRenderView.AR_4_3_FIT_PARENT: 104 | displayAspectRatio = 4.0f / 3.0f; 105 | if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) 106 | displayAspectRatio = 1.0f / displayAspectRatio; 107 | break; 108 | case IRenderView.AR_ASPECT_FIT_PARENT: 109 | case IRenderView.AR_ASPECT_FILL_PARENT: 110 | case IRenderView.AR_ASPECT_WRAP_CONTENT: 111 | default: 112 | displayAspectRatio = (float) mVideoWidth / (float) mVideoHeight; 113 | if (mVideoSarNum > 0 && mVideoSarDen > 0) 114 | displayAspectRatio = displayAspectRatio * mVideoSarNum / mVideoSarDen; 115 | break; 116 | } 117 | boolean shouldBeWider = displayAspectRatio > specAspectRatio; 118 | 119 | switch (mCurrentAspectRatio) { 120 | case IRenderView.AR_ASPECT_FIT_PARENT: 121 | case IRenderView.AR_16_9_FIT_PARENT: 122 | case IRenderView.AR_4_3_FIT_PARENT: 123 | if (shouldBeWider) { 124 | // too wide, fix width 125 | width = widthSpecSize; 126 | height = (int) (width / displayAspectRatio); 127 | } else { 128 | // too high, fix height 129 | height = heightSpecSize; 130 | width = (int) (height * displayAspectRatio); 131 | } 132 | break; 133 | case IRenderView.AR_ASPECT_FILL_PARENT: 134 | if (shouldBeWider) { 135 | // not high enough, fix height 136 | height = heightSpecSize; 137 | width = (int) (height * displayAspectRatio); 138 | } else { 139 | // not wide enough, fix width 140 | width = widthSpecSize; 141 | height = (int) (width / displayAspectRatio); 142 | } 143 | break; 144 | case IRenderView.AR_ASPECT_WRAP_CONTENT: 145 | default: 146 | if (shouldBeWider) { 147 | // too wide, fix width 148 | width = Math.min(mVideoWidth, widthSpecSize); 149 | height = (int) (width / displayAspectRatio); 150 | } else { 151 | // too high, fix height 152 | height = Math.min(mVideoHeight, heightSpecSize); 153 | width = (int) (height * displayAspectRatio); 154 | } 155 | break; 156 | } 157 | } else if (widthSpecMode == View.MeasureSpec.EXACTLY && heightSpecMode == View.MeasureSpec.EXACTLY) { 158 | // the size is fixed 159 | width = widthSpecSize; 160 | height = heightSpecSize; 161 | 162 | // for compatibility, we adjust size based on aspect ratio 163 | if (mVideoWidth * height < width * mVideoHeight) { 164 | //Log.i("@@@", "image too wide, correcting"); 165 | width = height * mVideoWidth / mVideoHeight; 166 | } else if (mVideoWidth * height > width * mVideoHeight) { 167 | //Log.i("@@@", "image too tall, correcting"); 168 | height = width * mVideoHeight / mVideoWidth; 169 | } 170 | } else if (widthSpecMode == View.MeasureSpec.EXACTLY) { 171 | // only the width is fixed, adjust the height to match aspect ratio if possible 172 | width = widthSpecSize; 173 | height = width * mVideoHeight / mVideoWidth; 174 | if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) { 175 | // couldn't match aspect ratio within the constraints 176 | height = heightSpecSize; 177 | } 178 | } else if (heightSpecMode == View.MeasureSpec.EXACTLY) { 179 | // only the height is fixed, adjust the width to match aspect ratio if possible 180 | height = heightSpecSize; 181 | width = height * mVideoWidth / mVideoHeight; 182 | if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) { 183 | // couldn't match aspect ratio within the constraints 184 | width = widthSpecSize; 185 | } 186 | } else { 187 | // neither the width nor the height are fixed, try to use actual video size 188 | width = mVideoWidth; 189 | height = mVideoHeight; 190 | if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) { 191 | // too tall, decrease both width and height 192 | height = heightSpecSize; 193 | width = height * mVideoWidth / mVideoHeight; 194 | } 195 | if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) { 196 | // too wide, decrease both width and height 197 | width = widthSpecSize; 198 | height = width * mVideoHeight / mVideoWidth; 199 | } 200 | } 201 | } else { 202 | // no size yet, just adopt the given spec sizes 203 | } 204 | 205 | mMeasuredWidth = width; 206 | mMeasuredHeight = height; 207 | } 208 | 209 | public int getMeasuredWidth() { 210 | return mMeasuredWidth; 211 | } 212 | 213 | public int getMeasuredHeight() { 214 | return mMeasuredHeight; 215 | } 216 | 217 | public void setAspectRatio(int aspectRatio) { 218 | mCurrentAspectRatio = aspectRatio; 219 | } 220 | 221 | @NonNull 222 | public static String getAspectRatioText(Context context, int aspectRatio) { 223 | String text; 224 | switch (aspectRatio) { 225 | case IRenderView.AR_ASPECT_FIT_PARENT: 226 | text = context.getString(R.string.VideoView_ar_aspect_fit_parent); 227 | break; 228 | case IRenderView.AR_ASPECT_FILL_PARENT: 229 | text = context.getString(R.string.VideoView_ar_aspect_fill_parent); 230 | break; 231 | case IRenderView.AR_ASPECT_WRAP_CONTENT: 232 | text = context.getString(R.string.VideoView_ar_aspect_wrap_content); 233 | break; 234 | case IRenderView.AR_MATCH_PARENT: 235 | text = context.getString(R.string.VideoView_ar_match_parent); 236 | break; 237 | case IRenderView.AR_16_9_FIT_PARENT: 238 | text = context.getString(R.string.VideoView_ar_16_9_fit_parent); 239 | break; 240 | case IRenderView.AR_4_3_FIT_PARENT: 241 | text = context.getString(R.string.VideoView_ar_4_3_fit_parent); 242 | break; 243 | default: 244 | text = context.getString(R.string.N_A); 245 | break; 246 | } 247 | return text; 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /videoplayer/src/com/ishow/videoplayer/widget/media/SurfaceRenderView.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 The yuhaiyang Android Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * @author: y.haiyang@qq.com 17 | */ 18 | 19 | package com.ishow.videoplayer.widget.media; 20 | 21 | import android.annotation.TargetApi; 22 | import android.content.Context; 23 | import android.graphics.SurfaceTexture; 24 | import android.os.Build; 25 | import android.support.annotation.NonNull; 26 | import android.support.annotation.Nullable; 27 | import android.util.AttributeSet; 28 | import android.util.Log; 29 | import android.view.Surface; 30 | import android.view.SurfaceHolder; 31 | import android.view.SurfaceView; 32 | import android.view.View; 33 | import android.view.accessibility.AccessibilityEvent; 34 | import android.view.accessibility.AccessibilityNodeInfo; 35 | 36 | import java.lang.ref.WeakReference; 37 | import java.util.Map; 38 | import java.util.concurrent.ConcurrentHashMap; 39 | 40 | import tv.danmaku.ijk.media.player.IMediaPlayer; 41 | import tv.danmaku.ijk.media.player.ISurfaceTextureHolder; 42 | 43 | public class SurfaceRenderView extends SurfaceView implements IRenderView { 44 | private MeasureHelper mMeasureHelper; 45 | 46 | public SurfaceRenderView(Context context) { 47 | super(context); 48 | initView(context); 49 | } 50 | 51 | public SurfaceRenderView(Context context, AttributeSet attrs) { 52 | super(context, attrs); 53 | initView(context); 54 | } 55 | 56 | public SurfaceRenderView(Context context, AttributeSet attrs, int defStyleAttr) { 57 | super(context, attrs, defStyleAttr); 58 | initView(context); 59 | } 60 | 61 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 62 | public SurfaceRenderView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 63 | super(context, attrs, defStyleAttr, defStyleRes); 64 | initView(context); 65 | } 66 | 67 | private void initView(Context context) { 68 | mMeasureHelper = new MeasureHelper(this); 69 | mSurfaceCallback = new SurfaceCallback(this); 70 | getHolder().addCallback(mSurfaceCallback); 71 | //noinspection deprecation 72 | getHolder().setType(SurfaceHolder.SURFACE_TYPE_NORMAL); 73 | } 74 | 75 | @Override 76 | public View getView() { 77 | return this; 78 | } 79 | 80 | @Override 81 | public boolean shouldWaitForResize() { 82 | return true; 83 | } 84 | 85 | //-------------------- 86 | // Layout & Measure 87 | //-------------------- 88 | @Override 89 | public void setVideoSize(int videoWidth, int videoHeight) { 90 | if (videoWidth > 0 && videoHeight > 0) { 91 | mMeasureHelper.setVideoSize(videoWidth, videoHeight); 92 | getHolder().setFixedSize(videoWidth, videoHeight); 93 | requestLayout(); 94 | } 95 | } 96 | 97 | @Override 98 | public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) { 99 | if (videoSarNum > 0 && videoSarDen > 0) { 100 | mMeasureHelper.setVideoSampleAspectRatio(videoSarNum, videoSarDen); 101 | requestLayout(); 102 | } 103 | } 104 | 105 | @Override 106 | public void setVideoRotation(int degree) { 107 | Log.e("", "SurfaceView doesn't support rotation (" + degree + ")!\n"); 108 | } 109 | 110 | @Override 111 | public void setAspectRatio(int aspectRatio) { 112 | mMeasureHelper.setAspectRatio(aspectRatio); 113 | requestLayout(); 114 | } 115 | 116 | @Override 117 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 118 | mMeasureHelper.doMeasure(widthMeasureSpec, heightMeasureSpec); 119 | setMeasuredDimension(mMeasureHelper.getMeasuredWidth(), mMeasureHelper.getMeasuredHeight()); 120 | } 121 | 122 | //-------------------- 123 | // SurfaceViewHolder 124 | //-------------------- 125 | 126 | private static final class InternalSurfaceHolder implements IRenderView.ISurfaceHolder { 127 | private SurfaceRenderView mSurfaceView; 128 | private SurfaceHolder mSurfaceHolder; 129 | 130 | public InternalSurfaceHolder(@NonNull SurfaceRenderView surfaceView, 131 | @Nullable SurfaceHolder surfaceHolder) { 132 | mSurfaceView = surfaceView; 133 | mSurfaceHolder = surfaceHolder; 134 | } 135 | 136 | public void bindToMediaPlayer(IMediaPlayer mp) { 137 | if (mp != null) { 138 | if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) && 139 | (mp instanceof ISurfaceTextureHolder)) { 140 | ISurfaceTextureHolder textureHolder = (ISurfaceTextureHolder) mp; 141 | textureHolder.setSurfaceTexture(null); 142 | } 143 | mp.setDisplay(mSurfaceHolder); 144 | } 145 | } 146 | 147 | @NonNull 148 | @Override 149 | public IRenderView getRenderView() { 150 | return mSurfaceView; 151 | } 152 | 153 | @Nullable 154 | @Override 155 | public SurfaceHolder getSurfaceHolder() { 156 | return mSurfaceHolder; 157 | } 158 | 159 | @Nullable 160 | @Override 161 | public SurfaceTexture getSurfaceTexture() { 162 | return null; 163 | } 164 | 165 | @Nullable 166 | @Override 167 | public Surface openSurface() { 168 | if (mSurfaceHolder == null) 169 | return null; 170 | return mSurfaceHolder.getSurface(); 171 | } 172 | } 173 | 174 | //------------------------- 175 | // SurfaceHolder.Callback 176 | //------------------------- 177 | 178 | @Override 179 | public void addRenderCallback(IRenderCallback callback) { 180 | mSurfaceCallback.addRenderCallback(callback); 181 | } 182 | 183 | @Override 184 | public void removeRenderCallback(IRenderCallback callback) { 185 | mSurfaceCallback.removeRenderCallback(callback); 186 | } 187 | 188 | private SurfaceCallback mSurfaceCallback; 189 | 190 | private static final class SurfaceCallback implements SurfaceHolder.Callback { 191 | private SurfaceHolder mSurfaceHolder; 192 | private boolean mIsFormatChanged; 193 | private int mFormat; 194 | private int mWidth; 195 | private int mHeight; 196 | 197 | private WeakReference mWeakSurfaceView; 198 | private Map mRenderCallbackMap = new ConcurrentHashMap(); 199 | 200 | public SurfaceCallback(@NonNull SurfaceRenderView surfaceView) { 201 | mWeakSurfaceView = new WeakReference(surfaceView); 202 | } 203 | 204 | public void addRenderCallback(@NonNull IRenderCallback callback) { 205 | mRenderCallbackMap.put(callback, callback); 206 | 207 | ISurfaceHolder surfaceHolder = null; 208 | if (mSurfaceHolder != null) { 209 | if (surfaceHolder == null) 210 | surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder); 211 | callback.onSurfaceCreated(surfaceHolder, mWidth, mHeight); 212 | } 213 | 214 | if (mIsFormatChanged) { 215 | if (surfaceHolder == null) 216 | surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder); 217 | callback.onSurfaceChanged(surfaceHolder, mFormat, mWidth, mHeight); 218 | } 219 | } 220 | 221 | public void removeRenderCallback(@NonNull IRenderCallback callback) { 222 | mRenderCallbackMap.remove(callback); 223 | } 224 | 225 | @Override 226 | public void surfaceCreated(SurfaceHolder holder) { 227 | mSurfaceHolder = holder; 228 | mIsFormatChanged = false; 229 | mFormat = 0; 230 | mWidth = 0; 231 | mHeight = 0; 232 | 233 | ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder); 234 | for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) { 235 | renderCallback.onSurfaceCreated(surfaceHolder, 0, 0); 236 | } 237 | } 238 | 239 | @Override 240 | public void surfaceDestroyed(SurfaceHolder holder) { 241 | mSurfaceHolder = null; 242 | mIsFormatChanged = false; 243 | mFormat = 0; 244 | mWidth = 0; 245 | mHeight = 0; 246 | 247 | ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder); 248 | for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) { 249 | renderCallback.onSurfaceDestroyed(surfaceHolder); 250 | } 251 | } 252 | 253 | @Override 254 | public void surfaceChanged(SurfaceHolder holder, int format, 255 | int width, int height) { 256 | mSurfaceHolder = holder; 257 | mIsFormatChanged = true; 258 | mFormat = format; 259 | mWidth = width; 260 | mHeight = height; 261 | 262 | // mMeasureHelper.setVideoSize(width, height); 263 | 264 | ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder); 265 | for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) { 266 | renderCallback.onSurfaceChanged(surfaceHolder, format, width, height); 267 | } 268 | } 269 | } 270 | 271 | //-------------------- 272 | // Accessibility 273 | //-------------------- 274 | 275 | @Override 276 | public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 277 | super.onInitializeAccessibilityEvent(event); 278 | event.setClassName(SurfaceRenderView.class.getName()); 279 | } 280 | 281 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) 282 | @Override 283 | public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 284 | super.onInitializeAccessibilityNodeInfo(info); 285 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 286 | info.setClassName(SurfaceRenderView.class.getName()); 287 | } 288 | } 289 | } 290 | --------------------------------------------------------------------------------