├── .gitignore
├── .idea
├── caches
│ └── build_file_checksums.ser
├── codeStyles
│ └── Project.xml
├── compiler.xml
├── encodings.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── LICENSE
├── README.md
├── app-debug.apk
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── anbetter
│ │ └── xplayer
│ │ ├── App.java
│ │ ├── LiveDemoActivity.java
│ │ ├── LiveListActivity.java
│ │ ├── LiveRoomActivity.java
│ │ ├── MainActivity.java
│ │ ├── ScrollingActivity.java
│ │ ├── VideoListAdapter.java
│ │ ├── XPlayerActivity.java
│ │ ├── discretescrollview
│ │ ├── DSVOrientation.java
│ │ ├── Direction.java
│ │ ├── DiscreteScrollLayoutManager.java
│ │ ├── DiscreteScrollView.java
│ │ ├── InfiniteScrollAdapter.java
│ │ ├── RecyclerViewProxy.java
│ │ ├── transform
│ │ │ ├── DiscreteScrollItemTransformer.java
│ │ │ ├── Pivot.java
│ │ │ └── ScaleTransformer.java
│ │ └── util
│ │ │ └── ScrollListenerAdapter.java
│ │ └── model
│ │ └── VideoInfo.java
│ └── res
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable-xhdpi
│ ├── default_play_img.png
│ ├── default_service_video_dot.png
│ ├── default_service_video_play_xiao.png
│ ├── default_service_video_suspend.png
│ └── default_service_xuanzhuan.png
│ ├── drawable-xxhdpi
│ ├── default_play_img.png
│ ├── default_service_video_dot.png
│ ├── default_service_video_play_xiao.png
│ ├── default_service_video_suspend.png
│ └── default_service_xuanzhuan.png
│ ├── drawable
│ ├── default_seekbar.xml
│ ├── default_seekbar_thumb.xml
│ ├── ic_launcher_background.xml
│ └── shape_do_bg.xml
│ ├── layout
│ ├── activity_live_demo.xml
│ ├── activity_live_list.xml
│ ├── activity_live_room.xml
│ ├── activity_main.xml
│ ├── activity_player.xml
│ ├── activity_scrolling.xml
│ └── live_list_item.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── images
├── demo_01.jpeg
├── demo_02.jpeg
├── demo_03.jpeg
├── demo_04.jpeg
├── demo_05.jpeg
└── demo_06.jpeg
├── settings.gradle
└── xplayer_ijk
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
└── main
├── AndroidManifest.xml
├── java
└── com
│ └── anbetter
│ └── xplayer
│ └── ijk
│ ├── TextureRenderView.java
│ ├── XDragVideoView.java
│ ├── XMediaPlayer.java
│ ├── XVideoControls.java
│ ├── XVideoView.java
│ ├── api
│ ├── IXMediaPlayer.java
│ ├── IXRenderView.java
│ └── IXVideoView.java
│ ├── delegate
│ └── XMediaPlayerDelegate.java
│ ├── listener
│ ├── IXVideoViewListener.java
│ ├── XMediaPlayerAdapterListener.java
│ └── XMediaPlayerListener.java
│ └── utils
│ ├── OrientationEventUtils.java
│ ├── ViewMeasureUtils.java
│ └── XUtils.java
└── res
├── drawable-xhdpi
├── btn_small_close_normal.png
├── btn_small_close_pressed.png
├── jz_add_volume.png
├── jz_back_normal.png
├── jz_back_pressed.png
├── jz_back_tiny_normal.png
├── jz_back_tiny_pressed.png
├── jz_backward_icon.png
├── jz_battery_level_10.png
├── jz_battery_level_100.png
├── jz_battery_level_30.png
├── jz_battery_level_50.png
├── jz_battery_level_70.png
├── jz_battery_level_90.png
├── jz_brightness_video.png
├── jz_clarity_popwindow_bg.9.png
├── jz_close_volume.png
├── jz_enlarge.png
├── jz_forward_icon.png
├── jz_loading_bg.png
├── jz_pause_normal.png
├── jz_pause_pressed.png
├── jz_play_normal.png
├── jz_play_pressed.png
├── jz_restart_normal.png
├── jz_restart_pressed.png
├── jz_share_normal.png
├── jz_share_pressed.png
├── jz_shrink.png
└── jz_volume_icon.png
├── drawable
├── btn_small_close_selector.xml
├── jz_click_pause_selector.xml
├── jz_click_play_selector.xml
└── jz_click_replay_selector.xml
├── layout
└── video_view_controls_layout.xml
└── values
├── ids.xml
└── strings.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | # *.apk
3 | # *.ap_
4 |
5 | # Files for the ART/Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Gradle files
17 | .gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | # Android Studio captures folder
33 | captures/
34 |
35 | # Intellij
36 | *.iml
37 | .idea/workspace.xml
38 | .idea/tasks.xml
39 | .idea/gradle.xml
40 | .idea/assetWizardSettings.xml
41 | .idea/dictionaries
42 | .idea/libraries
43 | .idea/caches
44 |
45 | # Keystore files
46 | # Uncomment the following line if you do not want to check your keystore files in.
47 | *.jks
48 |
49 | # External native build folder generated in Android Studio 2.2 and later
50 | .externalNativeBuild
51 |
52 | # Google Services (e.g. APIs or Firebase)
53 | google-services.json
54 |
--------------------------------------------------------------------------------
/.idea/caches/build_file_checksums.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/.idea/caches/build_file_checksums.ser
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
17 |
23 |
28 |
33 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app-debug.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/app-debug.apk
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 26
5 | defaultConfig {
6 | applicationId "com.youzu.xplayer"
7 | minSdkVersion 18
8 | targetSdkVersion 23
9 | versionCode 1
10 | versionName "1.0"
11 |
12 | ndk {
13 | abiFilters "armeabi-v7a"
14 | }
15 |
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 |
25 | // 强制改变所有引用com.android.support版本为27.1.0。
26 | configurations.all {
27 | resolutionStrategy.eachDependency { DependencyResolveDetails details ->
28 | def requested = details.requested
29 | if (requested.group == 'com.android.support') {
30 | if (!requested.name.startsWith("multidex")) {
31 | details.useVersion '27.1.0'
32 | }
33 | }
34 | }
35 | }
36 |
37 | }
38 |
39 | dependencies {
40 | implementation fileTree(include: ['*.jar'], dir: 'libs')
41 | implementation project(":xplayer_ijk")
42 |
43 | implementation 'com.facebook.fresco.helper:fresco-helper:2.0.5'
44 | implementation 'com.android.support:appcompat-v7:26.1.0'
45 | implementation 'com.android.support:design:26.1.0'
46 | implementation 'com.android.support.constraint:constraint-layout:1.1.0'
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 | * Created by android_ls on 2018/4/25. 11 | * 12 | * @author android_ls 13 | * @version 1.0 14 | */ 15 | public class App extends Application { 16 | 17 | @Override 18 | public void onCreate() { 19 | super.onCreate(); 20 | 21 | Phoenix.init(this); 22 | MLog.init(true, "MLog"); 23 | 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/anbetter/xplayer/LiveDemoActivity.java: -------------------------------------------------------------------------------- 1 | package com.anbetter.xplayer; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.view.View; 6 | 7 | import com.anbetter.xplayer.ijk.api.IXRenderView; 8 | import com.anbetter.xplayer.ijk.api.IXVideoView; 9 | 10 | /** 11 | * 视频播放器组件提供的基本功能示例Demo 12 | * 功能: 13 | * 1、支持播放直播流(rtmp) 14 | * 2、支持播放各种格式的多媒体(MP4、flv、MP3) 15 | * 3、支持多种视频画面显示方式:16:9、4:3、全屏、竖直居中等 16 | * 4、支持常用的动画(旋转、移动、缩放) 17 | * 5、支持倍速播放(加快或者减慢播放速度) 18 | *
19 | * Created by android_ls on 2018/4/23. 20 | * 21 | * @author android_ls 22 | * @version 1.0 23 | */ 24 | public class LiveDemoActivity extends AppCompatActivity { 25 | 26 | private IXVideoView mVideoView; 27 | private int mRotation; 28 | private boolean isPause; 29 | 30 | @Override 31 | protected void onCreate(Bundle savedInstanceState) { 32 | super.onCreate(savedInstanceState); 33 | setContentView(R.layout.activity_live_demo); 34 | 35 | // String videoPath = "rtmp://live.hkstv.hk.lxdns.com/live/hks"; 36 | String videoPath = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f30.mp4"; 37 | // String videoPath = "http://ips.ifeng.com/video19.ifeng.com/video09/2014/06/16/1989823-102-086-0009.mp4"; 38 | // String videoPath = "http://jzvd.nathen.cn/1b61da23555d4ce28c805ea303711aa5/7a33ac2af276441bb4b9838f32d8d710-5287d2089db37e62345123a1be272f8b.mp4"; 39 | 40 | 41 | mVideoView = findViewById(R.id.player_view); 42 | mVideoView.setDisplayAspectRatio(IXRenderView.AR_ASPECT_FIT_PARENT); 43 | // mVideoView.setDisplayAspectRatio(XIRenderView.AR_MATCH_PARENT); 44 | mVideoView.setVideoPath(videoPath); 45 | 46 | 47 | findViewById(R.id.btn_play).setOnClickListener(new View.OnClickListener() { 48 | @Override 49 | public void onClick(View v) { 50 | mVideoView.play(); 51 | } 52 | }); 53 | findViewById(R.id.btn_pause).setOnClickListener(new View.OnClickListener() { 54 | @Override 55 | public void onClick(View v) { 56 | mVideoView.pause(); 57 | } 58 | }); 59 | 60 | findViewById(R.id.btn_resume).setOnClickListener(new View.OnClickListener() { 61 | @Override 62 | public void onClick(View v) { 63 | mVideoView.resume(); 64 | } 65 | }); 66 | 67 | findViewById(R.id.btn_01).setOnClickListener(new View.OnClickListener() { 68 | @Override 69 | public void onClick(View v) { 70 | mVideoView.setDisplayAspectRatio(IXRenderView.AR_ASPECT_FILL_PARENT); 71 | } 72 | }); 73 | findViewById(R.id.btn_02).setOnClickListener(new View.OnClickListener() { 74 | @Override 75 | public void onClick(View v) { 76 | mVideoView.setDisplayAspectRatio(IXRenderView.AR_ASPECT_FIT_PARENT); 77 | } 78 | }); 79 | 80 | findViewById(R.id.btn_04).setOnClickListener(new View.OnClickListener() { 81 | @Override 82 | public void onClick(View v) { 83 | mVideoView.setDisplayAspectRatio(IXRenderView.AR_4_3_FIT_PARENT); 84 | } 85 | }); 86 | findViewById(R.id.btn_05).setOnClickListener(new View.OnClickListener() { 87 | @Override 88 | public void onClick(View v) { 89 | mVideoView.setDisplayAspectRatio(IXRenderView.AR_16_9_FIT_PARENT); 90 | } 91 | }); 92 | findViewById(R.id.btn_06).setOnClickListener(new View.OnClickListener() { 93 | @Override 94 | public void onClick(View v) { 95 | mVideoView.setDisplayAspectRatio(IXRenderView.AR_MATCH_PARENT); 96 | } 97 | }); 98 | 99 | findViewById(R.id.btn_speed_01).setOnClickListener(new View.OnClickListener() { 100 | @Override 101 | public void onClick(View v) { 102 | mVideoView.setSpeed(0.25f); 103 | } 104 | }); 105 | findViewById(R.id.btn_speed_02).setOnClickListener(new View.OnClickListener() { 106 | @Override 107 | public void onClick(View v) { 108 | mVideoView.setSpeed(0.5f); 109 | } 110 | }); 111 | findViewById(R.id.btn_speed_03).setOnClickListener(new View.OnClickListener() { 112 | @Override 113 | public void onClick(View v) { 114 | mVideoView.setSpeed(1.0f); 115 | } 116 | }); 117 | findViewById(R.id.btn_speed_04).setOnClickListener(new View.OnClickListener() { 118 | @Override 119 | public void onClick(View v) { 120 | mVideoView.setSpeed(1.5f); 121 | } 122 | }); 123 | findViewById(R.id.btn_speed_05).setOnClickListener(new View.OnClickListener() { 124 | @Override 125 | public void onClick(View v) { 126 | mVideoView.setSpeed(2.0f); 127 | } 128 | }); 129 | 130 | findViewById(R.id.btn_rotation_90).setOnClickListener(new View.OnClickListener() { 131 | @Override 132 | public void onClick(View v) { 133 | mRotation += 90; 134 | mVideoView.setVideoRotation(mRotation); 135 | 136 | if (mRotation == 360) { 137 | mRotation = 0; 138 | } 139 | } 140 | }); 141 | 142 | } 143 | 144 | @Override 145 | protected void onPause() { 146 | super.onPause(); 147 | if (mVideoView != null) { 148 | mVideoView.pause(); 149 | isPause = true; 150 | } 151 | } 152 | 153 | @Override 154 | protected void onResume() { 155 | super.onResume(); 156 | if (!isPause) { 157 | return; 158 | } 159 | 160 | if (mVideoView != null) { 161 | mVideoView.resume(); 162 | } 163 | } 164 | 165 | @Override 166 | protected void onDestroy() { 167 | if (mVideoView != null) { 168 | mVideoView.release(); 169 | } 170 | super.onDestroy(); 171 | } 172 | 173 | } 174 | -------------------------------------------------------------------------------- /app/src/main/java/com/anbetter/xplayer/LiveListActivity.java: -------------------------------------------------------------------------------- 1 | package com.anbetter.xplayer; 2 | 3 | import android.os.Bundle; 4 | import android.os.Handler; 5 | import android.os.Looper; 6 | import android.support.annotation.Nullable; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.support.v7.widget.RecyclerView; 9 | 10 | import com.anbetter.log.MLog; 11 | import com.anbetter.xplayer.discretescrollview.DSVOrientation; 12 | import com.anbetter.xplayer.discretescrollview.DiscreteScrollView; 13 | import com.anbetter.xplayer.discretescrollview.transform.ScaleTransformer; 14 | import com.anbetter.xplayer.ijk.delegate.XMediaPlayerDelegate; 15 | import com.anbetter.xplayer.model.VideoInfo; 16 | 17 | import java.util.ArrayList; 18 | 19 | /** 20 | * 直播列表示例Demo 21 | * 实现思路: 22 | * 1、列表中所有XIVideoView对象共享同一个XIMediaPlayer播放器对象 23 | * 2、从之前正在播放的卡片到新的将要播放的卡片,XIMediaPlayer播放器对象做的动作依次是stop、reset、 24 | * setVideoPath、setSurface、play 25 | * 3、XIMediaPlayer播放器对象创建非常消耗资源,所以推荐尽可能的共享 26 | *
27 | * Created by android_ls on 2018/4/23.
28 | *
29 | * @author android_ls
30 | * @version 1.0
31 | */
32 | public class LiveListActivity extends AppCompatActivity
33 | implements DiscreteScrollView.OnItemChangedListener
21 | * Created by android_ls on 2018/4/24.
22 | *
23 | * @author android_ls
24 | * @version 1.0
25 | */
26 | public class LiveRoomActivity extends AppCompatActivity {
27 |
28 | private IXVideoView mVideoView;
29 | private float scaleRatio = 1.0F; // 缩放比例
30 | private ObjectAnimator scaleAnimator;
31 | private boolean isPause;
32 |
33 | @Override
34 | protected void onCreate(Bundle savedInstanceState) {
35 | super.onCreate(savedInstanceState);
36 | requestWindowFeature(Window.FEATURE_NO_TITLE);
37 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
38 | WindowManager.LayoutParams.FLAG_FULLSCREEN);
39 | setContentView(R.layout.activity_live_room);
40 |
41 | Intent intent = getIntent();
42 | String videoUrl = intent.getStringExtra("url");
43 | if (TextUtils.isEmpty(videoUrl)) {
44 | return;
45 | }
46 |
47 | mVideoView = findViewById(R.id.video_view);
48 | mVideoView.setVideoPath(videoUrl);
49 | mVideoView.setLooping(false);
50 | mVideoView.setDisplayAspectRatio(IXRenderView.AR_ASPECT_FIT_PARENT);
51 | mVideoView.play();
52 |
53 | findViewById(R.id.btn_01).setOnClickListener(new View.OnClickListener() {
54 | @Override
55 | public void onClick(View v) {
56 | if (scaleRatio == 1.0f) {
57 | scale(0.5f);
58 | } else {
59 | scale(1.0f);
60 | }
61 | }
62 | });
63 | }
64 |
65 | @Override
66 | protected void onPause() {
67 | super.onPause();
68 | if (mVideoView != null) {
69 | mVideoView.pause();
70 | isPause = true;
71 | }
72 | }
73 |
74 | @Override
75 | protected void onResume() {
76 | super.onResume();
77 | if (!isPause) {
78 | return;
79 | }
80 |
81 | if (mVideoView != null) {
82 | mVideoView.resume();
83 | }
84 | }
85 |
86 | @Override
87 | protected void onDestroy() {
88 | if (mVideoView != null) {
89 | mVideoView.release();
90 | }
91 | super.onDestroy();
92 | }
93 |
94 | private void scale(float ratio) {
95 | if (scaleRatio == ratio) {
96 | return;
97 | }
98 |
99 | if (scaleAnimator != null) {
100 | scaleAnimator.cancel();
101 | }
102 |
103 | PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", scaleRatio, ratio);
104 | PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", scaleRatio, ratio);
105 | PropertyValuesHolder translationX = PropertyValuesHolder.ofFloat("translationX", 0);
106 | PropertyValuesHolder translationY = PropertyValuesHolder.ofFloat("translationY", 0);
107 | scaleAnimator = ObjectAnimator.ofPropertyValuesHolder(mVideoView, scaleX, scaleY, translationX, translationY);
108 | scaleAnimator.addListener(new AnimatorListenerAdapter() {
109 | @Override
110 | public void onAnimationEnd(Animator animation) {
111 | animation.removeAllListeners();
112 | scaleAnimator = null;
113 | }
114 | });
115 | scaleAnimator.setDuration(150L).start();
116 | scaleRatio = ratio;
117 | }
118 |
119 | }
120 |
--------------------------------------------------------------------------------
/app/src/main/java/com/anbetter/xplayer/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.anbetter.xplayer;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.view.View;
7 |
8 | public class MainActivity extends AppCompatActivity {
9 |
10 | @Override
11 | protected void onCreate(Bundle savedInstanceState) {
12 | super.onCreate(savedInstanceState);
13 | setContentView(R.layout.activity_main);
14 |
15 | findViewById(R.id.btn_01).setOnClickListener(new View.OnClickListener() {
16 | @Override
17 | public void onClick(View v) {
18 | startActivity(new Intent(MainActivity.this, LiveDemoActivity.class));
19 | }
20 | });
21 | findViewById(R.id.btn_02).setOnClickListener(new View.OnClickListener() {
22 | @Override
23 | public void onClick(View v) {
24 | startActivity(new Intent(MainActivity.this, LiveListActivity.class));
25 | }
26 | });
27 |
28 | findViewById(R.id.btn_03).setOnClickListener(new View.OnClickListener() {
29 | @Override
30 | public void onClick(View v) {
31 | String videoPath = "rtmp://live.hkstv.hk.lxdns.com/live/hks";
32 |
33 | Intent intent = new Intent(MainActivity.this, LiveRoomActivity.class);
34 | intent.putExtra("url", videoPath);
35 | startActivity(intent);
36 | }
37 | });
38 |
39 | findViewById(R.id.btn_06).setOnClickListener(new View.OnClickListener() {
40 | @Override
41 | public void onClick(View v) {
42 | startActivity(new Intent(MainActivity.this, ScrollingActivity.class));
43 | }
44 | });
45 |
46 | // findViewById(R.id.btn_04).setOnClickListener(new View.OnClickListener() {
47 | // @Override
48 | // public void onClick(View v) {
49 | // startActivity(new Intent(MainActivity.this, XPlayerActivity.class));
50 | // }
51 | // });
52 | //
53 | // findViewById(R.id.btn_05).setOnClickListener(new View.OnClickListener() {
54 | // @Override
55 | // public void onClick(View v) {
56 | //
57 | // }
58 | // });
59 | //
60 | // findViewById(R.id.btn_07).setOnClickListener(new View.OnClickListener() {
61 | // @Override
62 | // public void onClick(View v) {
63 | //
64 | // }
65 | // });
66 |
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/app/src/main/java/com/anbetter/xplayer/ScrollingActivity.java:
--------------------------------------------------------------------------------
1 | package com.anbetter.xplayer;
2 |
3 | import android.os.Bundle;
4 | import android.support.design.widget.AppBarLayout;
5 | import android.support.design.widget.CollapsingToolbarLayout;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.support.v7.widget.Toolbar;
8 | import android.view.View;
9 |
10 | import com.anbetter.xplayer.ijk.XDragVideoView;
11 | import com.anbetter.xplayer.ijk.api.IXMediaPlayer;
12 | import com.anbetter.xplayer.ijk.api.IXRenderView;
13 | import com.anbetter.xplayer.ijk.api.IXVideoView;
14 | import com.anbetter.xplayer.ijk.delegate.XMediaPlayerDelegate;
15 |
16 | /**
17 | * 大小视频窗口切换Demo
18 | * 实现思路:
19 | * 1、采用多个XIVideoView共享同一个XIMediaPlayer播放器对象
20 | * 2、在滚动结束后,为XIMediaPlayer对象设置当前显示XIVideoView所持有的Surface
21 | * 3、XIMediaPlayer播放器播放视频的动作从未停止,只是切换展示视频画面的Surface而已,从而实现无缝切换大小窗口的功能
22 | * 4、小窗口支持在屏幕任意位置拖动,在拖动过程中播放动作不中断。
23 | *
24 | * Created by android_ls on 2018/4/26.
25 | *
26 | * @author android_ls
27 | * @version 1.0
28 | */
29 | public class ScrollingActivity extends AppCompatActivity implements AppBarLayout.OnOffsetChangedListener {
30 |
31 | public static final int APP_BAR_LAYOUT_IDLE = 0;
32 | public static final int APP_BAR_LAYOUT_EXPANDED = 1;
33 | public static final int APP_BAR_LAYOUT_COLLAPSED = 2;
34 |
35 | private AppBarLayout mAppBarLayout;
36 | private CollapsingToolbarLayout mCollapsingToolbarLayout;
37 |
38 | private boolean isPause;
39 | private String videoUrl;
40 | private int mAppBarLayoutCurrentState = APP_BAR_LAYOUT_IDLE;
41 |
42 | private IXMediaPlayer mMediaPlayer;
43 | private IXVideoView mVideoView;
44 | private XDragVideoView mSmallVideoView;
45 |
46 | @Override
47 | protected void onCreate(Bundle savedInstanceState) {
48 | super.onCreate(savedInstanceState);
49 | setContentView(R.layout.activity_scrolling);
50 |
51 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
52 | setSupportActionBar(toolbar);
53 |
54 | mCollapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.toolbar_layout);
55 | mCollapsingToolbarLayout.setTitle("XPlayer");
56 |
57 | mAppBarLayout = (AppBarLayout) findViewById(R.id.app_bar);
58 | mAppBarLayout.addOnOffsetChangedListener(this);
59 |
60 | videoUrl = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f30.mp4";
61 |
62 | mSmallVideoView = findViewById(R.id.drag_video_view);
63 | mVideoView = findViewById(R.id.video_view);
64 |
65 | mMediaPlayer = XMediaPlayerDelegate.getInstance();
66 |
67 | mSmallVideoView.setMediaPlayer(mMediaPlayer);
68 | mSmallVideoView.setDisplayAspectRatio(IXRenderView.AR_MATCH_PARENT);
69 |
70 | mVideoView.setMediaPlayer(mMediaPlayer);
71 | mVideoView.setDisplayAspectRatio(IXRenderView.AR_MATCH_PARENT);
72 |
73 | mMediaPlayer.setVideoPath(videoUrl);
74 | mMediaPlayer.setLooping(false);
75 | mMediaPlayer.play();
76 | }
77 |
78 | @Override
79 | public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
80 | // MLog.i("verticalOffset = " + verticalOffset);
81 | if (verticalOffset == 0) {
82 | if (mAppBarLayoutCurrentState != APP_BAR_LAYOUT_EXPANDED) {
83 | mCollapsingToolbarLayout.setTitle("");
84 |
85 | if (mVideoView.getSurface() != null) {
86 | mMediaPlayer.setSurface(mVideoView.getSurface());
87 | }
88 |
89 | if (mSmallVideoView.getVisibility() == View.VISIBLE) {
90 | mSmallVideoView.setVisibility(View.GONE);
91 | }
92 |
93 | mAppBarLayoutCurrentState = APP_BAR_LAYOUT_EXPANDED;
94 | }
95 | } else if (Math.abs(verticalOffset) >= appBarLayout.getTotalScrollRange()) {
96 | if (mAppBarLayoutCurrentState != APP_BAR_LAYOUT_COLLAPSED) {
97 | mCollapsingToolbarLayout.setTitle("大小视频显示组件互动");
98 |
99 | if (mSmallVideoView.getVisibility() == View.GONE) {
100 | mSmallVideoView.setVisibility(View.VISIBLE);
101 | // 重置到初始化所在位置
102 | mSmallVideoView.restorePosition();
103 |
104 | if (mSmallVideoView.getSurface() != null) {
105 | mMediaPlayer.setSurface(mSmallVideoView.getSurface());
106 | }
107 | }
108 |
109 | mAppBarLayoutCurrentState = APP_BAR_LAYOUT_COLLAPSED;
110 | }
111 | } else {
112 | if (mAppBarLayoutCurrentState != APP_BAR_LAYOUT_IDLE) {
113 | if (mAppBarLayoutCurrentState == APP_BAR_LAYOUT_COLLAPSED) {
114 | // 中间状态
115 | mSmallVideoView.postDelayed(new Runnable() {
116 | @Override
117 | public void run() {
118 | if (mVideoView.getSurface() != null) {
119 | mMediaPlayer.setSurface(mVideoView.getSurface());
120 | }
121 |
122 | if (mSmallVideoView.getVisibility() == View.VISIBLE) {
123 | mSmallVideoView.setVisibility(View.GONE);
124 | }
125 | }
126 | }, 50);
127 | }
128 | mAppBarLayoutCurrentState = APP_BAR_LAYOUT_IDLE;
129 | }
130 | }
131 | }
132 |
133 | @Override
134 | protected void onPause() {
135 | super.onPause();
136 | if (mMediaPlayer != null) {
137 | mMediaPlayer.pause();
138 | isPause = true;
139 | }
140 | }
141 |
142 | @Override
143 | protected void onResume() {
144 | super.onResume();
145 | if (!isPause) {
146 | return;
147 | }
148 |
149 | if (mMediaPlayer != null) {
150 | mMediaPlayer.resume();
151 | }
152 | }
153 |
154 | @Override
155 | protected void onDestroy() {
156 | if (mMediaPlayer != null) {
157 | mMediaPlayer.release();
158 | }
159 | super.onDestroy();
160 | }
161 |
162 | }
163 |
--------------------------------------------------------------------------------
/app/src/main/java/com/anbetter/xplayer/VideoListAdapter.java:
--------------------------------------------------------------------------------
1 | package com.anbetter.xplayer;
2 |
3 | import android.content.Intent;
4 | import android.support.annotation.NonNull;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.TextView;
9 |
10 | import com.anbetter.log.MLog;
11 | import com.anbetter.xplayer.ijk.api.IXRenderView;
12 | import com.anbetter.xplayer.ijk.api.IXVideoView;
13 | import com.anbetter.xplayer.ijk.delegate.XMediaPlayerDelegate;
14 | import com.anbetter.xplayer.model.VideoInfo;
15 | import com.facebook.drawee.view.SimpleDraweeView;
16 | import com.facebook.fresco.helper.Phoenix;
17 |
18 | import java.util.ArrayList;
19 |
20 | /**
21 | * 视频列表数据适配器
22 | *
23 | * @author android_ls
24 | * @version 1.0
25 | *
26 | * Created by android_ls on 2018/4/23.
27 | */
28 | public class VideoListAdapter extends RecyclerView.Adapter
18 | * Created by android_ls on 2018/4/23.
19 | *
20 | * @author android_ls
21 | * @version 1.0
22 | */
23 | public class XPlayerActivity extends AppCompatActivity {
24 |
25 | private IXVideoView mVideoView;
26 | private int mRotation;
27 | private boolean isPause;
28 |
29 | @Override
30 | protected void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 | setContentView(R.layout.activity_player);
33 |
34 | // String videoPath = "rtmp://live.hkstv.hk.lxdns.com/live/hks";
35 | String videoPath = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f30.mp4";
36 | // String videoPath = "http://ips.ifeng.com/video19.ifeng.com/video09/2014/06/16/1989823-102-086-0009.mp4";
37 | // String videoPath = "http://jzvd.nathen.cn/1b61da23555d4ce28c805ea303711aa5/7a33ac2af276441bb4b9838f32d8d710-5287d2089db37e62345123a1be272f8b.mp4";
38 |
39 |
40 | mVideoView = findViewById(R.id.player_view);
41 | mVideoView.setDisplayAspectRatio(IXRenderView.AR_ASPECT_FIT_PARENT);
42 | mVideoView.setVideoPath(videoPath);
43 | mVideoView.play();
44 |
45 |
46 |
47 |
48 | // findViewById(R.id.btn_play).setOnClickListener(new View.OnClickListener() {
49 | // @Override
50 | // public void onClick(View v) {
51 | // mVideoView.play();
52 | // }
53 | // });
54 | // findViewById(R.id.btn_pause).setOnClickListener(new View.OnClickListener() {
55 | // @Override
56 | // public void onClick(View v) {
57 | // mVideoView.pause();
58 | // }
59 | // });
60 | //
61 | // findViewById(R.id.btn_resume).setOnClickListener(new View.OnClickListener() {
62 | // @Override
63 | // public void onClick(View v) {
64 | // mVideoView.resume();
65 | // }
66 | // });
67 | //
68 | // findViewById(R.id.btn_01).setOnClickListener(new View.OnClickListener() {
69 | // @Override
70 | // public void onClick(View v) {
71 | // mVideoView.setDisplayAspectRatio(IXRenderView.AR_ASPECT_FILL_PARENT);
72 | // }
73 | // });
74 | // findViewById(R.id.btn_02).setOnClickListener(new View.OnClickListener() {
75 | // @Override
76 | // public void onClick(View v) {
77 | // mVideoView.setDisplayAspectRatio(IXRenderView.AR_ASPECT_FIT_PARENT);
78 | // }
79 | // });
80 | // findViewById(R.id.btn_03).setOnClickListener(new View.OnClickListener() {
81 | // @Override
82 | // public void onClick(View v) {
83 | // mVideoView.setDisplayAspectRatio(IXRenderView.AR_ASPECT_WRAP_CONTENT);
84 | // }
85 | // });
86 | // findViewById(R.id.btn_04).setOnClickListener(new View.OnClickListener() {
87 | // @Override
88 | // public void onClick(View v) {
89 | // mVideoView.setDisplayAspectRatio(IXRenderView.AR_4_3_FIT_PARENT);
90 | // }
91 | // });
92 | // findViewById(R.id.btn_05).setOnClickListener(new View.OnClickListener() {
93 | // @Override
94 | // public void onClick(View v) {
95 | // mVideoView.setDisplayAspectRatio(IXRenderView.AR_16_9_FIT_PARENT);
96 | // }
97 | // });
98 | // findViewById(R.id.btn_06).setOnClickListener(new View.OnClickListener() {
99 | // @Override
100 | // public void onClick(View v) {
101 | // mVideoView.setDisplayAspectRatio(IXRenderView.AR_MATCH_PARENT);
102 | // }
103 | // });
104 | //
105 | // findViewById(R.id.btn_speed_01).setOnClickListener(new View.OnClickListener() {
106 | // @Override
107 | // public void onClick(View v) {
108 | // mVideoView.setSpeed(0.25f);
109 | // }
110 | // });
111 | // findViewById(R.id.btn_speed_02).setOnClickListener(new View.OnClickListener() {
112 | // @Override
113 | // public void onClick(View v) {
114 | // mVideoView.setSpeed(0.5f);
115 | // }
116 | // });
117 | // findViewById(R.id.btn_speed_03).setOnClickListener(new View.OnClickListener() {
118 | // @Override
119 | // public void onClick(View v) {
120 | // mVideoView.setSpeed(1.0f);
121 | // }
122 | // });
123 | // findViewById(R.id.btn_speed_04).setOnClickListener(new View.OnClickListener() {
124 | // @Override
125 | // public void onClick(View v) {
126 | // mVideoView.setSpeed(1.5f);
127 | // }
128 | // });
129 | // findViewById(R.id.btn_speed_05).setOnClickListener(new View.OnClickListener() {
130 | // @Override
131 | // public void onClick(View v) {
132 | // mVideoView.setSpeed(2.0f);
133 | // }
134 | // });
135 | //
136 | // findViewById(R.id.btn_rotation_90).setOnClickListener(new View.OnClickListener() {
137 | // @Override
138 | // public void onClick(View v) {
139 | // mRotation += 90;
140 | // mVideoView.setVideoRotation(mRotation);
141 | //
142 | // if (mRotation == 360) {
143 | // mRotation = 0;
144 | // }
145 | // }
146 | // });
147 |
148 | }
149 |
150 | @Override
151 | protected void onPause() {
152 | super.onPause();
153 | if (mVideoView != null) {
154 | mVideoView.pause();
155 | isPause = true;
156 | }
157 | }
158 |
159 | @Override
160 | protected void onResume() {
161 | super.onResume();
162 | if (!isPause) {
163 | return;
164 | }
165 |
166 | if (mVideoView != null) {
167 | mVideoView.resume();
168 | }
169 | }
170 |
171 | @Override
172 | protected void onDestroy() {
173 | if (mVideoView != null) {
174 | mVideoView.release();
175 | }
176 | super.onDestroy();
177 | }
178 |
179 | }
180 |
--------------------------------------------------------------------------------
/app/src/main/java/com/anbetter/xplayer/discretescrollview/DSVOrientation.java:
--------------------------------------------------------------------------------
1 | package com.anbetter.xplayer.discretescrollview;
2 |
3 | import android.graphics.Point;
4 | import android.view.View;
5 |
6 | /**
7 | * Created by yarolegovich on 16.03.2017.
8 | */
9 | public enum DSVOrientation {
10 |
11 | HORIZONTAL {
12 | @Override
13 | Helper createHelper() {
14 | return new HorizontalHelper();
15 | }
16 | },
17 | VERTICAL {
18 | @Override
19 | Helper createHelper() {
20 | return new VerticalHelper();
21 | }
22 | };
23 |
24 | //Package private
25 | abstract Helper createHelper();
26 |
27 | interface Helper {
28 |
29 | int getViewEnd(int recyclerWidth, int recyclerHeight);
30 |
31 | int getDistanceToChangeCurrent(int childWidth, int childHeight);
32 |
33 | void setCurrentViewCenter(Point recyclerCenter, int scrolled, Point outPoint);
34 |
35 | void shiftViewCenter(Direction direction, int shiftAmount, Point outCenter);
36 |
37 | int getFlingVelocity(int velocityX, int velocityY);
38 |
39 | int getPendingDx(int pendingScroll);
40 |
41 | int getPendingDy(int pendingScroll);
42 |
43 | void offsetChildren(int amount, RecyclerViewProxy lm);
44 |
45 | float getDistanceFromCenter(Point center, int viewCenterX, int viewCenterY);
46 |
47 | boolean isViewVisible(Point center, int halfWidth, int halfHeight, int endBound, int extraSpace);
48 |
49 | boolean hasNewBecomeVisible(DiscreteScrollLayoutManager lm);
50 |
51 | boolean canScrollVertically();
52 |
53 | boolean canScrollHorizontally();
54 | }
55 |
56 | protected static class HorizontalHelper implements Helper {
57 |
58 | @Override
59 | public int getViewEnd(int recyclerWidth, int recyclerHeight) {
60 | return recyclerWidth;
61 | }
62 |
63 | @Override
64 | public int getDistanceToChangeCurrent(int childWidth, int childHeight) {
65 | return childWidth;
66 | }
67 |
68 | @Override
69 | public void setCurrentViewCenter(Point recyclerCenter, int scrolled, Point outPoint) {
70 | int newX = recyclerCenter.x - scrolled;
71 | outPoint.set(newX, recyclerCenter.y);
72 | }
73 |
74 | @Override
75 | public void shiftViewCenter(Direction direction, int shiftAmount, Point outCenter) {
76 | int newX = outCenter.x + direction.applyTo(shiftAmount);
77 | outCenter.set(newX, outCenter.y);
78 | }
79 |
80 | @Override
81 | public boolean isViewVisible(
82 | Point viewCenter, int halfWidth, int halfHeight, int endBound,
83 | int extraSpace) {
84 | int viewLeft = viewCenter.x - halfWidth;
85 | int viewRight = viewCenter.x + halfWidth;
86 | return viewLeft < (endBound + extraSpace) && viewRight > -extraSpace;
87 | }
88 |
89 | @Override
90 | public boolean hasNewBecomeVisible(DiscreteScrollLayoutManager lm) {
91 | View firstChild = lm.getFirstChild(), lastChild = lm.getLastChild();
92 | int leftBound = -lm.getExtraLayoutSpace();
93 | int rightBound = lm.getWidth() + lm.getExtraLayoutSpace();
94 | boolean isNewVisibleFromLeft = lm.getDecoratedLeft(firstChild) > leftBound
95 | && lm.getPosition(firstChild) > 0;
96 | boolean isNewVisibleFromRight = lm.getDecoratedRight(lastChild) < rightBound
97 | && lm.getPosition(lastChild) < lm.getItemCount() - 1;
98 | return isNewVisibleFromLeft || isNewVisibleFromRight;
99 | }
100 |
101 | @Override
102 | public void offsetChildren(int amount, RecyclerViewProxy helper) {
103 | helper.offsetChildrenHorizontal(amount);
104 | }
105 |
106 | @Override
107 | public float getDistanceFromCenter(Point center, int viewCenterX, int viewCenterY) {
108 | return viewCenterX - center.x;
109 | }
110 |
111 | @Override
112 | public int getFlingVelocity(int velocityX, int velocityY) {
113 | return velocityX;
114 | }
115 |
116 | @Override
117 | public boolean canScrollHorizontally() {
118 | return true;
119 | }
120 |
121 | @Override
122 | public boolean canScrollVertically() {
123 | return false;
124 | }
125 |
126 | @Override
127 | public int getPendingDx(int pendingScroll) {
128 | return pendingScroll;
129 | }
130 |
131 | @Override
132 | public int getPendingDy(int pendingScroll) {
133 | return 0;
134 | }
135 | }
136 |
137 |
138 | protected static class VerticalHelper implements Helper {
139 |
140 | @Override
141 | public int getViewEnd(int recyclerWidth, int recyclerHeight) {
142 | return recyclerHeight;
143 | }
144 |
145 | @Override
146 | public int getDistanceToChangeCurrent(int childWidth, int childHeight) {
147 | return childHeight;
148 | }
149 |
150 | @Override
151 | public void setCurrentViewCenter(Point recyclerCenter, int scrolled, Point outPoint) {
152 | int newY = recyclerCenter.y - scrolled;
153 | outPoint.set(recyclerCenter.x, newY);
154 | }
155 |
156 | @Override
157 | public void shiftViewCenter(Direction direction, int shiftAmount, Point outCenter) {
158 | int newY = outCenter.y + direction.applyTo(shiftAmount);
159 | outCenter.set(outCenter.x, newY);
160 | }
161 |
162 | @Override
163 | public void offsetChildren(int amount, RecyclerViewProxy helper) {
164 | helper.offsetChildrenVertical(amount);
165 | }
166 |
167 | @Override
168 | public float getDistanceFromCenter(Point center, int viewCenterX, int viewCenterY) {
169 | return viewCenterY - center.y;
170 | }
171 |
172 | @Override
173 | public boolean isViewVisible(
174 | Point viewCenter, int halfWidth, int halfHeight, int endBound,
175 | int extraSpace) {
176 | int viewTop = viewCenter.y - halfHeight;
177 | int viewBottom = viewCenter.y + halfHeight;
178 | return viewTop < (endBound + extraSpace) && viewBottom > -extraSpace;
179 | }
180 |
181 | @Override
182 | public boolean hasNewBecomeVisible(DiscreteScrollLayoutManager lm) {
183 | View firstChild = lm.getFirstChild(), lastChild = lm.getLastChild();
184 | int topBound = -lm.getExtraLayoutSpace();
185 | int bottomBound = lm.getHeight() + lm.getExtraLayoutSpace();
186 | boolean isNewVisibleFromTop = lm.getDecoratedTop(firstChild) > topBound
187 | && lm.getPosition(firstChild) > 0;
188 | boolean isNewVisibleFromBottom = lm.getDecoratedBottom(lastChild) < bottomBound
189 | && lm.getPosition(lastChild) < lm.getItemCount() - 1;
190 | return isNewVisibleFromTop || isNewVisibleFromBottom;
191 | }
192 |
193 | @Override
194 | public int getFlingVelocity(int velocityX, int velocityY) {
195 | return velocityY;
196 | }
197 |
198 | @Override
199 | public boolean canScrollHorizontally() {
200 | return false;
201 | }
202 |
203 | @Override
204 | public boolean canScrollVertically() {
205 | return true;
206 | }
207 |
208 | @Override
209 | public int getPendingDx(int pendingScroll) {
210 | return 0;
211 | }
212 |
213 | @Override
214 | public int getPendingDy(int pendingScroll) {
215 | return pendingScroll;
216 | }
217 | }
218 |
219 | }
220 |
--------------------------------------------------------------------------------
/app/src/main/java/com/anbetter/xplayer/discretescrollview/Direction.java:
--------------------------------------------------------------------------------
1 | package com.anbetter.xplayer.discretescrollview;
2 |
3 | /**
4 | * Created by yarolegovich on 16.03.2017.
5 | */
6 | enum Direction {
7 |
8 | START {
9 | @Override
10 | public int applyTo(int delta) {
11 | return delta * -1;
12 | }
13 |
14 | @Override
15 | public boolean sameAs(int direction) {
16 | return direction < 0;
17 | }
18 | },
19 | END {
20 | @Override
21 | public int applyTo(int delta) {
22 | return delta;
23 | }
24 |
25 | @Override
26 | public boolean sameAs(int direction) {
27 | return direction > 0;
28 | }
29 | };
30 |
31 | public abstract int applyTo(int delta);
32 |
33 | public abstract boolean sameAs(int direction);
34 |
35 | public static Direction fromDelta(int delta) {
36 | return delta > 0 ? END : START;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/anbetter/xplayer/discretescrollview/DiscreteScrollView.java:
--------------------------------------------------------------------------------
1 | package com.anbetter.xplayer.discretescrollview;
2 |
3 | import android.content.Context;
4 | import android.support.annotation.IntRange;
5 | import android.support.annotation.NonNull;
6 | import android.support.annotation.Nullable;
7 | import android.support.v7.widget.RecyclerView;
8 | import android.util.AttributeSet;
9 | import android.view.View;
10 |
11 | import com.anbetter.xplayer.discretescrollview.transform.DiscreteScrollItemTransformer;
12 | import com.anbetter.xplayer.discretescrollview.util.ScrollListenerAdapter;
13 |
14 | import java.util.ArrayList;
15 | import java.util.List;
16 |
17 | /**
18 | * Created by yarolegovich on 18.02.2017.
19 | */
20 | @SuppressWarnings("unchecked")
21 | public class DiscreteScrollView extends RecyclerView {
22 |
23 | public static final int NO_POSITION = DiscreteScrollLayoutManager.NO_POSITION;
24 |
25 | private static final int DEFAULT_ORIENTATION = DSVOrientation.HORIZONTAL.ordinal();
26 |
27 | private DiscreteScrollLayoutManager layoutManager;
28 |
29 | private List
6 | * Created by android_ls on 2018/4/25.
7 | *
8 | * @author android_ls
9 | * @version 1.0
10 | */
11 | public class VideoInfo {
12 |
13 | public String videoUrl;
14 | public String coverUrl;
15 | public String desc;
16 |
17 | public VideoInfo() {
18 | }
19 |
20 | public VideoInfo(String videoUrl, String coverUrl) {
21 | this.videoUrl = videoUrl;
22 | this.coverUrl = coverUrl;
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
20 | * Created by android_ls on 2018/4/19.
21 | *
22 | * @author android_ls
23 | * @version 1.0
24 | */
25 | public class TextureRenderView extends TextureView implements TextureView.SurfaceTextureListener, IXRenderView {
26 |
27 | private ViewMeasureUtils mMeasureHelper;
28 | private Surface mSurface;
29 | private OnSurfaceStatusListener mOnSurfaceStatusListener;
30 |
31 | public TextureRenderView(Context context) {
32 | super(context);
33 | setup(context);
34 | }
35 |
36 | public TextureRenderView(Context context, AttributeSet attrs) {
37 | super(context, attrs);
38 | setup(context);
39 | }
40 |
41 | public TextureRenderView(Context context, AttributeSet attrs, int defStyleAttr) {
42 | super(context, attrs, defStyleAttr);
43 | setup(context);
44 | }
45 |
46 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
47 | public TextureRenderView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
48 | super(context, attrs, defStyleAttr, defStyleRes);
49 | setup(context);
50 | }
51 |
52 | private void setup(Context context) {
53 | mMeasureHelper = new ViewMeasureUtils(this);
54 | setSurfaceTextureListener(this);
55 | }
56 |
57 | @Override
58 | public View getView() {
59 | return this;
60 | }
61 |
62 | @Override
63 | public void setVideoSize(int videoWidth, int videoHeight) {
64 | if (videoWidth > 0 && videoHeight > 0) {
65 | mMeasureHelper.setVideoSize(videoWidth, videoHeight);
66 | requestLayout();
67 | }
68 | }
69 |
70 | @Override
71 | public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) {
72 | if (videoSarNum > 0 && videoSarDen > 0) {
73 | mMeasureHelper.setVideoSampleAspectRatio(videoSarNum, videoSarDen);
74 | requestLayout();
75 | }
76 | }
77 |
78 | @Override
79 | public void setVideoRotation(int degree) {
80 | mMeasureHelper.setVideoRotation(degree);
81 | setRotation(degree);
82 | }
83 |
84 | @Override
85 | public void setAspectRatio(int aspectRatio) {
86 | mMeasureHelper.setAspectRatio(aspectRatio);
87 | requestLayout();
88 | }
89 |
90 | @Override
91 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
92 | mMeasureHelper.measure(widthMeasureSpec, heightMeasureSpec);
93 | setMeasuredDimension(mMeasureHelper.getMeasuredWidth(), mMeasureHelper.getMeasuredHeight());
94 | }
95 |
96 | @Override
97 | public Surface getSurface() {
98 | return mSurface;
99 | }
100 |
101 | @Override
102 | public void setOnSurfaceStatusListener(OnSurfaceStatusListener onSurfaceStatusListener) {
103 | mOnSurfaceStatusListener = onSurfaceStatusListener;
104 | }
105 |
106 | @Override
107 | public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
108 | // 在SurfaceTexture准备使用时调用。
109 | MLog.i("================onSurfaceTextureAvailable");
110 |
111 | mSurface = new Surface(surface);
112 | if (mOnSurfaceStatusListener != null) {
113 | MLog.i("=========22=======onSurfaceTextureAvailable");
114 | mOnSurfaceStatusListener.onSurfaceCreated(mSurface, width, height);
115 | }
116 | }
117 |
118 | @Override
119 | public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
120 | // 当SurfaceTexture缓冲区大小更改时调用。
121 | MLog.i("================onSurfaceTextureSizeChanged");
122 |
123 | if (mOnSurfaceStatusListener != null) {
124 | MLog.i("========22========onSurfaceTextureSizeChanged");
125 | mOnSurfaceStatusListener.onSurfaceSizeChanged(mSurface, width, height);
126 | }
127 | }
128 |
129 | @Override
130 | public void onSurfaceTextureUpdated(SurfaceTexture surface) {
131 | // MLog.i("================onSurfaceTextureUpdated");
132 | // 当指定SurfaceTexture的更新时调用updateTexImage()。
133 | }
134 |
135 | @Override
136 | public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
137 | // 当指定SurfaceTexture即将被销毁时调用。如果返回true,则调用此方法后,表面纹理中不会发生渲染。
138 | // 如果返回false,则客户端需要调用release()。大多数应用程序应该返回true。
139 | MLog.i("================onSurfaceTextureDestroyed");
140 |
141 | if (mOnSurfaceStatusListener != null) {
142 | MLog.i("=========22=======onSurfaceTextureDestroyed");
143 | mOnSurfaceStatusListener.onSurfaceDestroyed(mSurface);
144 | }
145 | return true;
146 | }
147 |
148 | }
149 |
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/java/com/anbetter/xplayer/ijk/XDragVideoView.java:
--------------------------------------------------------------------------------
1 | package com.anbetter.xplayer.ijk;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.graphics.PointF;
6 | import android.support.annotation.NonNull;
7 | import android.support.annotation.Nullable;
8 | import android.util.AttributeSet;
9 | import android.view.MotionEvent;
10 | import android.view.Surface;
11 | import android.view.View;
12 | import android.view.ViewConfiguration;
13 | import android.view.ViewGroup;
14 | import android.widget.FrameLayout;
15 | import android.widget.ImageView;
16 |
17 | import com.anbetter.xplayer.ijk.api.IXMediaPlayer;
18 | import com.anbetter.xplayer.ijk.api.IXVideoView;
19 | import com.anbetter.xplayer.ijk.listener.IXVideoViewListener;
20 | import com.anbetter.xplayer.ijk.utils.XUtils;
21 |
22 | /**
23 | * 视频播放器组件,支持在屏幕上任意拖动
24 | *
25 | * Created by android_ls on 2018/4/26.
26 | *
27 | * @author android_ls
28 | * @version 1.0
29 | */
30 | public class XDragVideoView extends FrameLayout implements IXVideoView {
31 |
32 | private boolean disableTrans;
33 | private int moveTouchSlop;
34 | private float lastTouchX;
35 | private float lastTouchY;
36 | private PointF dragTouchPoint;
37 |
38 | private XVideoView mVideoView;
39 |
40 | public XDragVideoView(@NonNull Context context) {
41 | super(context);
42 | setup(context);
43 | }
44 |
45 | public XDragVideoView(@NonNull Context context, @Nullable AttributeSet attrs) {
46 | super(context, attrs);
47 | setup(context);
48 | }
49 |
50 | protected void setup(Context context) {
51 | // 这行必须添加,否则除了ACTION_DOWN外的其它手势事件将扑捉不到
52 | setClickable(true);
53 |
54 | moveTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
55 | mVideoView = new XVideoView(context);
56 | addView(mVideoView, new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
57 | ViewGroup.LayoutParams.MATCH_PARENT));
58 |
59 | ImageView ivClose = new ImageView(context);
60 | ivClose.setImageResource(R.drawable.btn_small_close_selector);
61 | int padding = XUtils.dp2px(context, 3);
62 | ivClose.setPadding(padding, padding, padding, padding);
63 | ivClose.setLayoutParams(new LayoutParams(XUtils.dp2px(context, 30), XUtils.dp2px(context, 30)));
64 | addView(ivClose);
65 |
66 | ivClose.setOnClickListener(new View.OnClickListener() {
67 | @Override
68 | public void onClick(View v) {
69 | stop();
70 | setVisibility(View.GONE);
71 | }
72 | });
73 | }
74 |
75 | /**
76 | * 重置到初始化所在位置
77 | */
78 | public void restorePosition() {
79 | setTranslationX(0);
80 | setTranslationY(0);
81 | }
82 |
83 | @Override
84 | public boolean onInterceptTouchEvent(MotionEvent ev) {
85 | final float touchX = ev.getRawX();
86 | final float touchY = ev.getRawY();
87 | switch (ev.getActionMasked()) {
88 | case MotionEvent.ACTION_DOWN:
89 | case MotionEvent.ACTION_POINTER_DOWN:
90 | disableTrans = false;
91 | lastTouchX = touchX;
92 | lastTouchY = touchY;
93 | dragTouchPoint = new PointF(touchX, touchY);
94 | return false;
95 | case MotionEvent.ACTION_MOVE:
96 | float dx = Math.abs(touchX - dragTouchPoint.x);
97 | float dy = Math.abs(touchY - dragTouchPoint.y);
98 | return dx >= moveTouchSlop || dy >= moveTouchSlop;
99 | default:
100 | }
101 | return super.onInterceptTouchEvent(ev);
102 | }
103 |
104 | @Override
105 | @SuppressLint("ClickableViewAccessibility")
106 | public boolean onTouchEvent(MotionEvent event) {
107 | boolean consumed = false;
108 | float x = event.getRawX();
109 | float y = event.getRawY();
110 | switch (event.getActionMasked()) {
111 | case MotionEvent.ACTION_MOVE:
112 | if (!disableTrans) {
113 | float dx = x - lastTouchX;
114 | float dy = y - lastTouchY;
115 | float transX = getTranslationX() + dx;
116 | float transY = getTranslationY() + dy;
117 | setTranslationX(transX);
118 | setTranslationY(transY);
119 |
120 | lastTouchX = x;
121 | lastTouchY = y;
122 | consumed = true;
123 | }
124 | break;
125 | case MotionEvent.ACTION_UP:
126 | case MotionEvent.ACTION_POINTER_UP:
127 | if (event.getPointerId(event.getActionIndex()) == 0) {
128 | disableTrans = true;
129 | }
130 | break;
131 |
132 | default:
133 | }
134 | return consumed || super.onTouchEvent(event);
135 | }
136 |
137 | @Override
138 | public void setVideoPath(@NonNull String path) {
139 | mVideoView.setVideoPath(path);
140 | }
141 |
142 | @Override
143 | public void setCoverView(@NonNull View view) {
144 | mVideoView.setCoverView(view);
145 | }
146 |
147 | @Override
148 | public void setMediaPlayer(IXMediaPlayer mediaPlayer) {
149 | mVideoView.setMediaPlayer(mediaPlayer);
150 | }
151 |
152 | @Override
153 | public void setDisplayAspectRatio(int displayAspectRatio) {
154 | mVideoView.setDisplayAspectRatio(displayAspectRatio);
155 | }
156 |
157 | @Override
158 | public void setVideoRotation(int degree) {
159 | mVideoView.setVideoRotation(degree);
160 | }
161 |
162 | @Override
163 | public void setLooping(boolean looping) {
164 | mVideoView.setLooping(looping);
165 | }
166 |
167 | @Override
168 | public int getCurrentState() {
169 | return mVideoView.getCurrentState();
170 | }
171 |
172 | @Override
173 | public boolean isPlaying() {
174 | return mVideoView.isPlaying();
175 | }
176 |
177 | @Override
178 | public int getDuration() {
179 | return mVideoView.getDuration();
180 | }
181 |
182 | @Override
183 | public int getCurrentPosition() {
184 | return mVideoView.getCurrentPosition();
185 | }
186 |
187 | @Override
188 | public void setNeedMute(boolean needMute) {
189 | mVideoView.setNeedMute(needMute);
190 | }
191 |
192 | @Override
193 | public void seekTo(long pos) {
194 | mVideoView.seekTo(pos);
195 | }
196 |
197 | @Override
198 | public void setSpeed(float speed) {
199 | mVideoView.setSpeed(speed);
200 | }
201 |
202 | @Override
203 | public void setVideoViewListener(IXVideoViewListener listener) {
204 | mVideoView.setVideoViewListener(listener);
205 | }
206 |
207 | @Override
208 | public Surface getSurface() {
209 | return mVideoView.getSurface();
210 | }
211 |
212 | @Override
213 | public void play() {
214 | mVideoView.play();
215 | }
216 |
217 | @Override
218 | public void pause() {
219 | mVideoView.pause();
220 | }
221 |
222 | @Override
223 | public void resume() {
224 | mVideoView.resume();
225 | }
226 |
227 | @Override
228 | public void stop() {
229 | mVideoView.stop();
230 | }
231 |
232 | @Override
233 | public void release() {
234 | mVideoView.release();
235 | }
236 |
237 | }
238 |
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/java/com/anbetter/xplayer/ijk/XVideoControls.java:
--------------------------------------------------------------------------------
1 | package com.anbetter.xplayer.ijk;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.widget.FrameLayout;
8 | import android.widget.ImageView;
9 | import com.anbetter.xplayer.ijk.api.IXVideoView;
10 |
11 | /**
12 | *
13 | * Created by android_ls on 2018/5/8.
14 | *
15 | * @author android_ls
16 | * @version 1.0
17 | */
18 | public class XVideoControls extends FrameLayout {
19 |
20 | private IXVideoView mVideoView;
21 | private ImageView iv_start;
22 |
23 | public XVideoControls(Context context) {
24 | super(context);
25 | setup(context);
26 | }
27 |
28 | public XVideoControls(Context context, AttributeSet attrs) {
29 | super(context, attrs);
30 | setup(context);
31 | }
32 |
33 | protected void setup(Context context) {
34 | LayoutInflater.from(context).inflate(R.layout.video_view_controls_layout, this);
35 | iv_start = findViewById(R.id.iv_start);
36 | iv_start.setOnClickListener(new View.OnClickListener() {
37 | @Override
38 | public void onClick(View v) {
39 | if(mVideoView == null) {
40 | return;
41 | }
42 |
43 | if(mVideoView.isPlaying()) {
44 | iv_start.setImageResource(R.drawable.jz_click_pause_selector);
45 | mVideoView.pause();
46 | } else {
47 | iv_start.setImageResource(R.drawable.jz_click_play_selector);
48 | mVideoView.play();
49 | }
50 | }
51 | });
52 | }
53 |
54 | public void setVideoView(IXVideoView videoView) {
55 | this.mVideoView = videoView;
56 | }
57 |
58 | public void show() {
59 |
60 | }
61 |
62 | public void hide() {
63 |
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/java/com/anbetter/xplayer/ijk/api/IXMediaPlayer.java:
--------------------------------------------------------------------------------
1 | package com.anbetter.xplayer.ijk.api;
2 |
3 | import android.view.Surface;
4 | import com.anbetter.xplayer.ijk.listener.XMediaPlayerListener;
5 |
6 | /**
7 | * 视频播放器
8 | *
9 | * Created by android_ls on 2018/4/18.
10 | *
11 | * @author android_ls
12 | * @version 1.0
13 | */
14 | public interface IXMediaPlayer {
15 |
16 | /**
17 | * 出错了
18 | */
19 | int STATE_ERROR = -1;
20 |
21 | /**
22 | * 空闲状态、闲置的
23 | */
24 | int STATE_IDLE = 0;
25 |
26 | /**
27 | * 准备中
28 | */
29 | int STATE_PREPARING = 1;
30 |
31 | /**
32 | * 准备好了
33 | */
34 | int STATE_PREPARED = 2;
35 |
36 | /**
37 | * 播放中
38 | */
39 | int STATE_PLAYING = 3;
40 |
41 | /**
42 | * 暂停
43 | */
44 | int STATE_PAUSED = 4;
45 |
46 | /**
47 | * 播放结束
48 | */
49 | int STATE_COMPLETED = 5;
50 |
51 | /**
52 | * 设置播放地址
53 | *
54 | * @param path
55 | */
56 | void setVideoPath(String path);
57 |
58 | /**
59 | * 获取Surface对象
60 | */
61 | Surface getSurface();
62 |
63 | /**
64 | * 设置Surface
65 | *
66 | * @param surface
67 | */
68 | void setSurface(Surface surface);
69 |
70 | /**
71 | * 释放Surface对象
72 | */
73 | void releaseSurface();
74 |
75 | /**
76 | * 是否循环播放
77 | *
78 | * @param looping
79 | */
80 | void setLooping(boolean looping);
81 |
82 | /**
83 | * 播放器当前处所状态
84 | *
85 | * @return 其返回值有以下几个:
86 | * @see #STATE_ERROR
87 | * @see #STATE_IDLE
88 | * @see #STATE_PREPARING
89 | * @see #STATE_PREPARED
90 | * @see #STATE_PLAYING
91 | * @see #STATE_PAUSED
92 | * @see #STATE_COMPLETED
93 | */
94 | int getCurrentState();
95 |
96 | /**
97 | * 是否正在播放
98 | *
99 | * @return true表示正在播放
100 | */
101 | boolean isPlaying();
102 |
103 | /**
104 | * 获取播放文件总时间
105 | *
106 | * @return
107 | */
108 | int getDuration();
109 |
110 | /**
111 | * 获取当前播放的进度值(当前播放到哪儿了)
112 | *
113 | * @return 当前播放位置
114 | */
115 | int getCurrentPosition();
116 |
117 | /**
118 | * 设置是否静音
119 | *
120 | * @param needMute true表示开启静音模式
121 | */
122 | void setNeedMute(boolean needMute);
123 |
124 | /**
125 | * 设置当前的播放进度
126 | *
127 | * @param pos
128 | */
129 | void seekTo(long pos);
130 |
131 | /**
132 | * 设置视频的播放速度
133 | *
134 | * @param speed 默认值1.0
135 | */
136 | void setSpeed(float speed);
137 |
138 | /**
139 | * 设置视频播放器,在播放过程中的事件回调监听器
140 | *
141 | * @param mediaPlayerListener XMediaPlayerListener
142 | */
143 | void setMediaPlayerListener(XMediaPlayerListener mediaPlayerListener);
144 |
145 | void play();
146 |
147 | void start();
148 |
149 | void pause();
150 |
151 | void resume();
152 |
153 | void stop();
154 |
155 | void reset();
156 |
157 | /**
158 | * 该方法推荐在XIVideoView#release()方法中调用
159 | */
160 | void release();
161 |
162 | int getVideoWidth();
163 |
164 | int getVideoHeight();
165 |
166 | int getVideoSarNum();
167 |
168 | int getVideoSarDen();
169 |
170 | }
171 |
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/java/com/anbetter/xplayer/ijk/api/IXRenderView.java:
--------------------------------------------------------------------------------
1 | package com.anbetter.xplayer.ijk.api;
2 |
3 | import android.view.Surface;
4 | import android.view.View;
5 |
6 | /**
7 | * 视频画面视图(视频画面渲染视图)
8 | *
9 | * Created by android_ls on 2018/4/19.
10 | *
11 | * @author android_ls
12 | * @version 1.0
13 | */
14 | public interface IXRenderView {
15 |
16 | /**
17 | * 水平方向拉伸填满屏幕,竖直方向居中
18 | */
19 | int AR_ASPECT_FIT_PARENT = 0;
20 |
21 | /**
22 | * 拉伸到填充满指定尺寸,对视频画面居中裁剪
23 | */
24 | int AR_ASPECT_FILL_PARENT = 1;
25 |
26 | /**
27 | * 保持视频内容的原始尺寸
28 | */
29 | int AR_ASPECT_WRAP_CONTENT = 2;
30 |
31 | /**
32 | * 拉伸到填充满指定尺寸
33 | */
34 | int AR_MATCH_PARENT = 3;
35 |
36 | /**
37 | * 宽高比16:9,宽是填充满指定的尺寸的
38 | */
39 | int AR_16_9_FIT_PARENT = 4;
40 |
41 | /**
42 | * 宽高比4:3,宽是填充满指定的尺寸的
43 | */
44 | int AR_4_3_FIT_PARENT = 5;
45 |
46 | View getView();
47 |
48 | Surface getSurface();
49 |
50 | void setOnSurfaceStatusListener(OnSurfaceStatusListener onSurfaceStatusListener);
51 |
52 | void setAspectRatio(int aspectRatio);
53 |
54 | void setVideoSize(int videoWidth, int videoHeight);
55 |
56 | void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen);
57 |
58 | /**
59 | * 只针对TextureRenderView组件起作用
60 | *
61 | * @param degree
62 | */
63 | void setVideoRotation(int degree);
64 |
65 | interface OnSurfaceStatusListener {
66 | void onSurfaceCreated(Surface surface, int width, int height);
67 |
68 | void onSurfaceSizeChanged(Surface surface, int width, int height);
69 |
70 | void onSurfaceDestroyed(Surface surface);
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/java/com/anbetter/xplayer/ijk/api/IXVideoView.java:
--------------------------------------------------------------------------------
1 | package com.anbetter.xplayer.ijk.api;
2 |
3 | import android.support.annotation.NonNull;
4 | import android.view.Surface;
5 | import android.view.View;
6 | import com.anbetter.xplayer.ijk.listener.IXVideoViewListener;
7 |
8 | /**
9 | * 视频播放器组件
10 | *
11 | * Created by android_ls on 2018/4/23.
12 | *
13 | * @author android_ls
14 | * @version 1.0
15 | */
16 | public interface IXVideoView {
17 |
18 | /**
19 | * 设置播放地址
20 | *
21 | * @param path
22 | */
23 | void setVideoPath(@NonNull String path);
24 |
25 | /**
26 | * 设置视频未播放前的预览画面(视频封面)
27 | *
28 | * @param view
29 | */
30 | void setCoverView(@NonNull View view);
31 |
32 | /**
33 | * 设置音视频播放器
34 | *
35 | * 备注:
36 | * 1、每一个XIVideoView对象默认内置一个XIMediaPlayer对象
37 | * 2、当且仅当想让多个XIVideoView对象共用同一个XIMediaPlayer对象时,调用该方法进行设置
38 | * 3、若不需要XIMediaPlayer对象进行共享的话,调用或者不调用这个方法,效果一致。
39 | *
40 | * @param mediaPlayer XIMediaPlayer
41 | */
42 | void setMediaPlayer(IXMediaPlayer mediaPlayer);
43 |
44 | /**
45 | * 设置显示的比例
46 | */
47 | void setDisplayAspectRatio(int displayAspectRatio);
48 |
49 | /**
50 | * 只针对TextureRenderView组件起作用
51 | *
52 | * @param degree
53 | */
54 | void setVideoRotation(int degree);
55 |
56 | /**
57 | * 是否循环播放
58 | *
59 | * @param looping
60 | */
61 | void setLooping(boolean looping);
62 |
63 | /**
64 | * 设置是否静音
65 | *
66 | * @param needMute true表示开启静音模式
67 | */
68 | void setNeedMute(boolean needMute);
69 |
70 | /**
71 | * 设置当前的播放进度
72 | *
73 | * @param pos
74 | */
75 | void seekTo(long pos);
76 |
77 | /**
78 | * 设置视频的播放速度
79 | *
80 | * @param speed 默认值1.0
81 | */
82 | void setSpeed(float speed);
83 |
84 | /**
85 | * 设置Video当前状态监听器
86 | * @param listener
87 | */
88 | void setVideoViewListener(IXVideoViewListener listener);
89 |
90 | /**
91 | * 获取当前XIVideoView所持有的Surface对象
92 | *
93 | * @return
94 | */
95 | Surface getSurface();
96 |
97 | /**
98 | * 播放器当前处所状态
99 | */
100 | int getCurrentState();
101 |
102 | /**
103 | * 是否正在播放
104 | *
105 | * @return true表示正在播放
106 | */
107 | boolean isPlaying();
108 |
109 | /**
110 | * 获取播放文件总时间
111 | *
112 | * @return
113 | */
114 | int getDuration();
115 |
116 | /**
117 | * 获取当前播放的进度值(当前播放到哪儿了)
118 | *
119 | * @return 当前播放位置
120 | */
121 | int getCurrentPosition();
122 |
123 | void play();
124 |
125 | void pause();
126 |
127 | void resume();
128 |
129 | void stop();
130 |
131 | /**
132 | * 该方法推荐在Activity#onDestroy()方法中调用
133 | */
134 | void release();
135 |
136 | }
137 |
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/java/com/anbetter/xplayer/ijk/delegate/XMediaPlayerDelegate.java:
--------------------------------------------------------------------------------
1 | package com.anbetter.xplayer.ijk.delegate;
2 |
3 | import android.view.Surface;
4 |
5 | import com.anbetter.log.MLog;
6 | import com.anbetter.xplayer.ijk.XMediaPlayer;
7 | import com.anbetter.xplayer.ijk.api.IXMediaPlayer;
8 | import com.anbetter.xplayer.ijk.listener.XMediaPlayerListener;
9 |
10 | /**
11 | * 提供了视频播放器类的单例对象,可供多个XIVideoView对象共享
12 | *
13 | * Created by android_ls on 2018/4/27.
14 | *
15 | * @author android_ls
16 | * @version 1.0
17 | * @see IXMediaPlayer#setMediaPlayerListener(XMediaPlayerListener)
18 | */
19 | public class XMediaPlayerDelegate implements IXMediaPlayer {
20 |
21 | private static XMediaPlayerDelegate sXMediaPlayerManager;
22 | private IXMediaPlayer mMediaPlayer;
23 |
24 | private XMediaPlayerDelegate() {
25 | mMediaPlayer = new XMediaPlayer();
26 | MLog.i("-----XMediaPlayerDelegate--------");
27 | }
28 |
29 | public static XMediaPlayerDelegate getInstance() {
30 | if (sXMediaPlayerManager == null) {
31 | synchronized (XMediaPlayerDelegate.class) {
32 | if (sXMediaPlayerManager == null) {
33 | sXMediaPlayerManager = new XMediaPlayerDelegate();
34 | }
35 | }
36 | }
37 | return sXMediaPlayerManager;
38 | }
39 |
40 | public IXMediaPlayer getMediaPlayer() {
41 | return mMediaPlayer;
42 | }
43 |
44 | @Override
45 | public void setVideoPath(String path) {
46 | if (mMediaPlayer != null) {
47 | mMediaPlayer.setVideoPath(path);
48 | }
49 | }
50 |
51 | @Override
52 | public Surface getSurface() {
53 | if (mMediaPlayer != null) {
54 | return mMediaPlayer.getSurface();
55 | }
56 | return null;
57 | }
58 |
59 | @Override
60 | public void setSurface(Surface surface) {
61 | if (mMediaPlayer != null) {
62 | mMediaPlayer.setSurface(surface);
63 | }
64 | }
65 |
66 | @Override
67 | public void releaseSurface() {
68 | if (mMediaPlayer != null) {
69 | mMediaPlayer.releaseSurface();
70 | }
71 | }
72 |
73 | @Override
74 | public void setLooping(boolean looping) {
75 | if (mMediaPlayer != null) {
76 | mMediaPlayer.setLooping(looping);
77 | }
78 | }
79 |
80 | @Override
81 | public int getCurrentState() {
82 | if (mMediaPlayer != null) {
83 | return mMediaPlayer.getCurrentState();
84 | }
85 | return 0;
86 | }
87 |
88 | @Override
89 | public boolean isPlaying() {
90 | if (mMediaPlayer != null) {
91 | return mMediaPlayer.isPlaying();
92 | }
93 | return false;
94 | }
95 |
96 | @Override
97 | public int getDuration() {
98 | if (mMediaPlayer != null) {
99 | return mMediaPlayer.getDuration();
100 | }
101 | return 0;
102 | }
103 |
104 | @Override
105 | public int getCurrentPosition() {
106 | if (mMediaPlayer != null) {
107 | return mMediaPlayer.getCurrentPosition();
108 | }
109 | return 0;
110 | }
111 |
112 | @Override
113 | public void setNeedMute(boolean needMute) {
114 | if (mMediaPlayer != null) {
115 | mMediaPlayer.setNeedMute(needMute);
116 | }
117 | }
118 |
119 | @Override
120 | public void seekTo(long pos) {
121 | if (mMediaPlayer != null) {
122 | mMediaPlayer.seekTo(pos);
123 | }
124 | }
125 |
126 | @Override
127 | public void setSpeed(float speed) {
128 | if (mMediaPlayer != null) {
129 | mMediaPlayer.setSpeed(speed);
130 | }
131 | }
132 |
133 | @Override
134 | public void setMediaPlayerListener(XMediaPlayerListener mediaPlayerListener) {
135 | if (mMediaPlayer != null) {
136 | mMediaPlayer.setMediaPlayerListener(mediaPlayerListener);
137 | }
138 | }
139 |
140 | @Override
141 | public void play() {
142 | if (mMediaPlayer != null) {
143 | mMediaPlayer.play();
144 | }
145 | }
146 |
147 | @Override
148 | public void start() {
149 | if (mMediaPlayer != null) {
150 | mMediaPlayer.start();
151 | }
152 | }
153 |
154 | @Override
155 | public void pause() {
156 | if (mMediaPlayer != null) {
157 | mMediaPlayer.pause();
158 | }
159 | }
160 |
161 | @Override
162 | public void resume() {
163 | if (mMediaPlayer != null) {
164 | mMediaPlayer.resume();
165 | }
166 | }
167 |
168 | @Override
169 | public void stop() {
170 | if (mMediaPlayer != null) {
171 | mMediaPlayer.stop();
172 | }
173 | }
174 |
175 | @Override
176 | public void reset() {
177 | if (mMediaPlayer != null) {
178 | mMediaPlayer.reset();
179 | }
180 | }
181 |
182 | /**
183 | * 该方法在外部最好不要直接调用
184 | */
185 | @Override
186 | public void release() {
187 | if (mMediaPlayer != null) {
188 | mMediaPlayer.release();
189 | mMediaPlayer = null;
190 | }
191 | }
192 |
193 | @Override
194 | public int getVideoWidth() {
195 | if (mMediaPlayer != null) {
196 | return mMediaPlayer.getVideoWidth();
197 | }
198 | return 0;
199 | }
200 |
201 | @Override
202 | public int getVideoHeight() {
203 | if (mMediaPlayer != null) {
204 | return mMediaPlayer.getVideoHeight();
205 | }
206 | return 0;
207 | }
208 |
209 | @Override
210 | public int getVideoSarNum() {
211 | if (mMediaPlayer != null) {
212 | return mMediaPlayer.getVideoSarNum();
213 | }
214 | return 0;
215 | }
216 |
217 | @Override
218 | public int getVideoSarDen() {
219 | if (mMediaPlayer != null) {
220 | return mMediaPlayer.getVideoSarDen();
221 | }
222 | return 0;
223 | }
224 |
225 | /**
226 | * 该方法推荐在Activity#onDestroy()方法中调用
227 | */
228 | public void destroy() {
229 | MLog.i("-----XMediaPlayerDelegate--destroy------");
230 |
231 | release();
232 | if (sXMediaPlayerManager != null) {
233 | sXMediaPlayerManager = null;
234 | }
235 | }
236 |
237 | }
238 |
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/java/com/anbetter/xplayer/ijk/listener/IXVideoViewListener.java:
--------------------------------------------------------------------------------
1 | package com.anbetter.xplayer.ijk.listener;
2 |
3 | /**
4 | * Video当前状态监听器
5 | *
6 | * Created by android_ls on 2018/5/8.
7 | *
8 | * @author android_ls
9 | * @version 1.0
10 | */
11 | public interface IXVideoViewListener {
12 |
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/java/com/anbetter/xplayer/ijk/listener/XMediaPlayerAdapterListener.java:
--------------------------------------------------------------------------------
1 | package com.anbetter.xplayer.ijk.listener;
2 |
3 | import com.anbetter.xplayer.ijk.api.IXMediaPlayer;
4 |
5 | /**
6 | * 视频播放器,播放状态监听器实现类
7 | *
8 | * Created by android_ls on 2018/4/24.
9 | *
10 | * @author android_ls
11 | * @version 1.0
12 | */
13 | public class XMediaPlayerAdapterListener implements XMediaPlayerListener {
14 |
15 | @Override
16 | public void onPrepared(IXMediaPlayer mp) {
17 |
18 | }
19 |
20 | @Override
21 | public void onBufferingUpdate(int percent) {
22 |
23 | }
24 |
25 | @Override
26 | public void onSeekComplete() {
27 |
28 | }
29 |
30 | @Override
31 | public void onError(int what, int extra) {
32 |
33 | }
34 |
35 | @Override
36 | public void onInfo(int what, int extra) {
37 |
38 | }
39 |
40 | @Override
41 | public void onVideoSizeChanged(IXMediaPlayer mp, int width, int height, int sarNum, int sarDe) {
42 |
43 | }
44 |
45 | @Override
46 | public void onCompletion() {
47 |
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/java/com/anbetter/xplayer/ijk/listener/XMediaPlayerListener.java:
--------------------------------------------------------------------------------
1 | package com.anbetter.xplayer.ijk.listener;
2 | import com.anbetter.xplayer.ijk.api.IXMediaPlayer;
3 |
4 | /**
5 | * 视频播放器,播放状态监听器
6 | *
7 | * Created by android_ls on 2018/4/24.
8 | *
9 | * @author android_ls
10 | * @version 1.0
11 | */
12 | public interface XMediaPlayerListener {
13 |
14 | void onPrepared(IXMediaPlayer mp);
15 |
16 | void onBufferingUpdate(int percent);
17 |
18 | void onSeekComplete();
19 |
20 | void onError(int what, int extra);
21 |
22 | void onInfo(int what, int extra);
23 |
24 | void onVideoSizeChanged(IXMediaPlayer mp, int width, int height, int sarNum, int sarDe);
25 |
26 | void onCompletion();
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/java/com/anbetter/xplayer/ijk/utils/OrientationEventUtils.java:
--------------------------------------------------------------------------------
1 | package com.anbetter.xplayer.ijk.utils;
2 |
3 |
4 | import android.app.Activity;
5 | import android.content.Context;
6 | import android.content.pm.ActivityInfo;
7 | import android.provider.Settings;
8 | import android.view.OrientationEventListener;
9 |
10 | /**
11 | * 手机屏幕方向管理器
12 | *
13 | * Created by android_ls on 2018/4/23.
14 | *
15 | * @author android_ls
16 | * @version 1.0
17 | */
18 | public class OrientationEventUtils extends OrientationEventListener {
19 |
20 | private Context mContext;
21 | private OnScreenOrientationListener mScreenOrientationListener;
22 | private boolean mClick;
23 |
24 | // 0-竖屏,1-横屏,2-反向横屏
25 | private int mOrientationType;
26 | // 当前屏幕方向(当前手机竖着,但是屏幕为横屏)
27 | private int mCurrentScreenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
28 |
29 | public OrientationEventUtils(Context context, OnScreenOrientationListener listener) {
30 | super(context);
31 | this.mContext = context;
32 | this.mScreenOrientationListener = listener;
33 | }
34 |
35 | @Override
36 | public void onOrientationChanged(int rotation) {
37 | // 在系统设置里,设置的是否锁定屏幕方向,返回true表示根据手机旋转方向而切换横竖屏
38 | boolean autoRotateOn = (Settings.System.getInt(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0) == 1);
39 | if (!autoRotateOn) {
40 | return;
41 | }
42 |
43 | if (((rotation >= 0) && (rotation <= 30)) || (rotation >= 330)) {
44 | if (mClick) {
45 | if (mOrientationType > 0) {
46 | return;
47 | }
48 |
49 | mClick = false;
50 | mOrientationType = 0;
51 | } else {
52 | if (mOrientationType > 0) {
53 | // 切换为竖屏
54 | mCurrentScreenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
55 | ((Activity) mContext).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
56 | mOrientationType = 0;
57 | mClick = false;
58 |
59 | if (mScreenOrientationListener != null) {
60 | mScreenOrientationListener.onScreenOrientationChange(mCurrentScreenOrientation);
61 | }
62 | }
63 | }
64 | } else if (((rotation >= 230) && (rotation <= 310))) {
65 | if (mClick) {
66 | if (mOrientationType != 1) {
67 | return;
68 | }
69 |
70 | mClick = false;
71 | mOrientationType = 1;
72 | } else {
73 | if (!(mOrientationType == 1)) {
74 | // 设置为横屏
75 | mCurrentScreenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
76 | ((Activity) mContext).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
77 | mOrientationType = 1;
78 | mClick = false;
79 |
80 | if (mScreenOrientationListener != null) {
81 | mScreenOrientationListener.onScreenOrientationChange(mCurrentScreenOrientation);
82 | }
83 | }
84 | }
85 | } else if (rotation > 30 && rotation < 95) {
86 | if (mClick) {
87 | if (mOrientationType != 2) {
88 | return;
89 | }
90 |
91 | mClick = false;
92 | mOrientationType = 2;
93 | } else if (mOrientationType != 2) {
94 | // 设置为反向横屏
95 | mCurrentScreenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
96 | ((Activity) mContext).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
97 | mOrientationType = 2;
98 | mClick = false;
99 |
100 | if (mScreenOrientationListener != null) {
101 | mScreenOrientationListener.onScreenOrientationChange(mCurrentScreenOrientation);
102 | }
103 | }
104 | }
105 | }
106 |
107 | /**
108 | * 横竖屏切换,从竖屏-->横屏,从横屏-->竖屏
109 | */
110 | public void switchScreenOrientation() {
111 | mClick = true;
112 | if (mOrientationType == 0) {
113 | mCurrentScreenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
114 | ((Activity) mContext).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
115 | mOrientationType = 1;
116 | } else {
117 | mCurrentScreenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
118 | ((Activity) mContext).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
119 | mOrientationType = 0;
120 | }
121 |
122 | if (mScreenOrientationListener != null) {
123 | mScreenOrientationListener.onScreenOrientationChange(mCurrentScreenOrientation);
124 | }
125 | }
126 |
127 | public interface OnScreenOrientationListener {
128 | /**
129 | * 获取屏幕的当前方向
130 | *
131 | * @param orientation ActivityInfo.SCREEN_ORIENTATION_PORTRAIT、ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
132 | */
133 | void onScreenOrientationChange(int orientation);
134 | }
135 |
136 | }
137 |
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/java/com/anbetter/xplayer/ijk/utils/ViewMeasureUtils.java:
--------------------------------------------------------------------------------
1 | package com.anbetter.xplayer.ijk.utils;
2 |
3 | import android.view.View;
4 | import com.anbetter.xplayer.ijk.api.IXRenderView;
5 | import java.lang.ref.WeakReference;
6 |
7 | /**
8 | * 视频画面比例调整帮助类
9 | *
10 | * Created by android_ls on 2018/4/19.
11 | *
12 | * @author android_ls
13 | * @version 1.0
14 | */
15 | public class ViewMeasureUtils {
16 |
17 | private WeakReference
13 | * Created by android_ls on 2018/4/26.
14 | *
15 | * @author android_ls
16 | * @version 1.0
17 | */
18 | public class XUtils {
19 |
20 | public static int getDisplayWidth(@NonNull Context context) {
21 | return context.getResources().getDisplayMetrics().widthPixels;
22 | }
23 |
24 | public static int getDisplayHeight(@NonNull Context context) {
25 | return context.getResources().getDisplayMetrics().heightPixels;
26 | }
27 |
28 | public static int dp2px(Context context, float dip) {
29 | Resources r = context.getResources();
30 | float px = TypedValue.applyDimension(COMPLEX_UNIT_DIP, dip,
31 | r.getDisplayMetrics());
32 | return (int) px;
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/btn_small_close_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/btn_small_close_normal.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/btn_small_close_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/btn_small_close_pressed.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_add_volume.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_add_volume.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_back_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_back_normal.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_back_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_back_pressed.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_back_tiny_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_back_tiny_normal.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_back_tiny_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_back_tiny_pressed.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_backward_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_backward_icon.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_battery_level_10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_battery_level_10.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_battery_level_100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_battery_level_100.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_battery_level_30.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_battery_level_30.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_battery_level_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_battery_level_50.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_battery_level_70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_battery_level_70.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_battery_level_90.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_battery_level_90.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_brightness_video.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_brightness_video.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_clarity_popwindow_bg.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_clarity_popwindow_bg.9.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_close_volume.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_close_volume.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_enlarge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_enlarge.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_forward_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_forward_icon.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_loading_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_loading_bg.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_pause_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_pause_normal.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_pause_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_pause_pressed.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_play_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_play_normal.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_play_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_play_pressed.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_restart_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_restart_normal.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_restart_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_restart_pressed.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_share_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_share_normal.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_share_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_share_pressed.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_shrink.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_shrink.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable-xhdpi/jz_volume_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hpdx/XPlayer2/06c16fc1d72fe275a6726655b7d6b777c9d39104/xplayer_ijk/src/main/res/drawable-xhdpi/jz_volume_icon.png
--------------------------------------------------------------------------------
/xplayer_ijk/src/main/res/drawable/btn_small_close_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |