├── .gitignore
├── .idea
├── modules.xml
├── modules
│ └── SimplePlayer.iml
└── vcs.xml
├── README.md
├── build.gradle
├── demo
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── video
│ │ └── demo
│ │ ├── DemoApp.java
│ │ ├── MainActivity.java
│ │ ├── ScreenConvertor.java
│ │ ├── VideoAdapter.java
│ │ └── VideoPagerAdapter.java
│ └── res
│ ├── layout
│ ├── activity_main.xml
│ ├── player_layout.xml
│ ├── vh_video.xml
│ └── vh_viewpager.xml
│ ├── raw
│ └── intro.mp4
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── lib-simpleplayer
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── uis
│ │ └── lib
│ │ └── simpleplayer
│ │ ├── OnScreenListener.java
│ │ ├── PlayerLayout.java
│ │ ├── PlayerStateCallback.java
│ │ ├── Vlog.java
│ │ ├── bitmap
│ │ ├── OnBitmapListener.java
│ │ └── PlayerBitmap.java
│ │ └── player
│ │ ├── BasePlayerLayout.java
│ │ ├── PlayerCallback.java
│ │ ├── PlayerComplete.java
│ │ ├── PlayerControl.java
│ │ ├── PlayerCounter.java
│ │ ├── PlayerEntity.java
│ │ ├── PlayerListener.java
│ │ ├── PlayerUtils.java
│ │ └── PlayerView.java
│ └── res
│ ├── drawable
│ ├── bg_black_trans.xml
│ ├── btn_video_back.xml
│ ├── btn_video_close.xml
│ ├── btn_video_restart.xml
│ ├── color_bt_back.xml
│ ├── color_pb_red.xml
│ ├── color_pb_white.xml
│ ├── color_pb_white_trans.xml
│ ├── pb_video_gray.xml
│ ├── pb_video_progress.xml
│ ├── sbar_thumb_normal.xml
│ ├── sbar_thumb_pressed.xml
│ └── sbar_video_thumb.xml
│ ├── layout
│ └── video_player_layout.xml
│ ├── mipmap-xhdpi
│ ├── video_back_normal.png
│ ├── video_back_pressed.png
│ ├── video_close_normal.png
│ ├── video_close_pressed.png
│ ├── video_restart_normal.png
│ └── video_restart_pressed.png
│ ├── mipmap-xxhdpi
│ ├── fullscreen_exit.png
│ ├── fullscreen_start.png
│ ├── video_pause.png
│ ├── video_play.png
│ └── video_play_s.png
│ └── values
│ ├── video_attrs.xml
│ └── video_ids.xml
├── settings.gradle
└── snapshot
├── 2017-1.png
├── 2017-11.png
├── 2017-12.png
├── 2017-2.png
├── 2017-3.png
├── device-2017-001.png
├── device-2017-002.png
└── device-2017-003.png
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | .idea
5 | .DS_Store
6 | /build
7 | /captures
8 | .externalNativeBuild
9 | gradlew.bat
10 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/modules/SimplePlayer.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SimplePlayer
2 | AD Player simulate Tmall(广告播放器,模仿天猫,支持全屏,支持在线和离线播放,支持RecyclerView)
3 |
4 | ### 手机自带的MediaPlayer,支持http,https,rtsp
5 |
6 | ### 播放器原理
7 | 1.只有唯一的MediaPlayer和Surface在工作,切换视频会复用,内存消耗非常小
8 | 3.Surface创建使用的是Application.Context,Actiivty关闭不会对其持有引用
9 | 3.全屏切换会复用Surface防止卡顿,MediaPlayer随url变化,只保持一个
10 | 4.全屏切换通过Windows.ID_ANDROID_CONTENT 加上一个viewgroup
11 | a.全屏横屏
12 | ViewGroup.setSystemUiVisibility(SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
13 | Activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
14 | b.退出横屏
15 | ViewGroup.setSystemUiVisibility(SYSTEM_UI_FLAG_VISIBLE);
16 | Activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
17 |
18 | # Use
19 | compile 'com.uis:lib-simpleplayer:0.2.0'
20 | # Version
21 | 0.0.2 init library
22 | 0.0.5 fixed Databinding Confilect,make demo like Tmall
23 | 0.0.6 fixed fullscreen hide the thumb picture
24 | 0.0.7 fixed screen change,make video resize
25 | 0.1.4 fixed fullscreen bug, add network dnymic changed,add thumb scaleType and holder
26 | 0.1.6 fixed全屏小画面,支持销毁PlayerView
27 | 0.1.8 fixed全屏小画面不能自适应,自动销毁资源
28 | 0.2.0 stable
29 | # 效果图
30 | 
31 |
32 | 
33 |
34 | 
35 |
36 | 
37 |
38 | 
39 |
40 | 
41 |
42 | 
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | google()
6 | jcenter()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:2.3.3'
10 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'
11 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | google()
18 | jcenter()
19 | //maven {url 'https://jcenter.bintray.com'}
20 | maven{url 'https://dl.bintray.com/sweet/maven'}
21 | }
22 | }
23 |
24 | task clean(type: Delete) {
25 | delete rootProject.buildDir
26 | }
27 | ext {
28 | compileVer = 23
29 | buildVer = '25.0.0'
30 | minVer = 19
31 | targetVer = 25
32 | supportVer = '24.2.1'
33 | }
34 |
--------------------------------------------------------------------------------
/demo/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/demo/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion compileVer
5 | buildToolsVersion buildVer
6 |
7 |
8 | defaultConfig {
9 | applicationId "com.video.demo"
10 | minSdkVersion minVer
11 | targetSdkVersion targetVer
12 | versionCode 1
13 | versionName "1.0"
14 | ndk {
15 | //选择要添加的对应cpu类型的.so库。
16 | abiFilters 'armeabi'//'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64', 'mips', 'mips64','armeabi'
17 | }
18 | }
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 | dataBinding {
26 | enabled false
27 | }
28 | }
29 |
30 | dependencies {
31 | compile fileTree(dir: 'libs', include: ['*.jar'])
32 | compile 'com.android.support:recyclerview-v7:'+supportVer
33 | compile 'com.android.support:design:'+supportVer
34 | //compile 'com.facebook.fresco:fresco:1.5.0'
35 | compile project(':lib-simpleplayer')
36 | //compile 'com.uis:lib-simpleplayer:0.0.2'
37 | }
38 |
--------------------------------------------------------------------------------
/demo/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 /Users/lhb/Library/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 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/demo/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
16 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/video/demo/DemoApp.java:
--------------------------------------------------------------------------------
1 | package com.video.demo;
2 |
3 | import android.app.Application;
4 |
5 | import com.facebook.drawee.backends.pipeline.Fresco;
6 | import com.uis.lib.simpleplayer.Vlog;
7 |
8 | //import com.facebook.drawee.backends.pipeline.Fresco;
9 |
10 | /**
11 | * Created by lhb on 2017/7/25.
12 | */
13 |
14 | public class DemoApp extends Application {
15 | @Override
16 | public void onCreate() {
17 | super.onCreate();
18 | Vlog.enableDebug();
19 | Fresco.initialize(this);
20 | }
21 |
22 | public final static String URL = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1511769786707&di=a903cd0bc48d1ba8c5da5e530708ab61&imgtype=0&src=http%3A%2F%2Fa.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F58ee3d6d55fbb2fbbb8058d8464a20a44723dc55.jpg";
23 |
24 | public static String[] mUrl = {
25 | "https://lmbsy.qq.com/flv/140/144/n0025l026va.mp4?sdtfrom=v1103&guid=8bc05ce6e4511a28a4d1b44ed110ff6f&vkey=C9527C07C187684A3D8CE17094A6B9DBCBCDD3AF71E66197C0345A43A1E5999E233543F2717B0A6768E6B95FE7CB8C8C043E518C4FC405D7BBA3D3FBF2BC25BC7AAA94A4622BA6A716DD4FBBB72CEA6B28678DE718AAEA5EF8FF0C949BBC53B0272AC396B53981013AE721DF259D08F8989D5B7B4F612B7A&platform=2",
26 | "http://data.vod.itc.cn/?rb=1&prot=1&key=jbZhEJhlqlUN-Wj_HEI8BjaVqKNFvDrn&prod=flash&pt=1&new=/51/116/UdKGIuSjQIO8dynrybyS1E.mp4",
27 | "https://vdse.bdstatic.com//6a90cf9678713ea594a428a8c98d2b5f.mp4?authorization=bce-auth-v1%2Ffb297a5cc0fb434c971b8fa103e8dd7b%2F2017-05-11T09%3A02%3A31Z%2F-1%2F%2F385d02679b636d6e5dd150193a497b787d517afef0f6c0903350a85056408e59",
28 | "http://data.vod.itc.cn/?rb=1&prot=1&key=jbZhEJhlqlUN-Wj_HEI8BjaVqKNFvDrn&prod=flash&pt=1&new=/20/111/bOT648IiIIVJPS33wZpYWH.mp4",
29 | "http://jzvd.nathen.cn/6ea7357bc3fa4658b29b7933ba575008/fbbba953374248eb913cb1408dc61d85-5287d2089db37e62345123a1be272f8b.mp4",
30 | };
31 | }
32 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/video/demo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.video.demo;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.support.v7.widget.LinearLayoutManager;
7 | import android.support.v7.widget.RecyclerView;
8 | import android.view.View;
9 | import android.widget.Button;
10 |
11 | import com.uis.lib.simpleplayer.Vlog;
12 | import com.uis.lib.simpleplayer.player.PlayerUtils;
13 | import com.uis.lib.simpleplayer.PlayerLayout;
14 |
15 | import java.io.File;
16 | import java.io.FileOutputStream;
17 | import java.io.InputStream;
18 | import java.io.OutputStream;
19 |
20 | public class MainActivity extends AppCompatActivity {
21 |
22 | String[] mIcon = {"http://pic.qiantucdn.com/58pic/19/59/29/86g58PICRd3_1024.jpg",
23 | "http://pic.90sjimg.com/back_pic/qk/back_origin_pic/00/03/14/c0391a6c1efab3fe00911b04e8cedca4.jpg"};
24 |
25 | @Override
26 | protected void onCreate(Bundle savedInstanceState) {
27 | super.onCreate(savedInstanceState);
28 | setContentView(R.layout.activity_main);
29 | PlayerLayout playerLayout = id(R.id.player_id);
30 | RecyclerView recyclerView = id(R.id.recycler_view);
31 | Button btOpen = id(R.id.bt_open);
32 | btOpen.setOnClickListener(new View.OnClickListener() {
33 | @Override
34 | public void onClick(View v) {
35 | startActivity(new Intent(v.getContext(),MainActivity.class));
36 | }
37 | });
38 | boolean isList = true;
39 | if(isList) {
40 | playerLayout.setVisibility(View.GONE);
41 | LinearLayoutManager layoutManager = new LinearLayoutManager(this);
42 | recyclerView.setLayoutManager(layoutManager);
43 | VideoAdapter adapter = new VideoAdapter();
44 | int size = DemoApp.mUrl.length;
45 | String[] data = new String[1*size+2];
46 | data[0] = "";
47 | for(int i = 1,t = 1*size+1;i 0) {
59 | os.write(buff);
60 | }
61 | os.flush();
62 | os.close();
63 | is.close();
64 | }
65 | }catch (Exception ex){
66 | ex.printStackTrace();
67 | }
68 | adapter.setData(data);
69 | recyclerView.setAdapter(adapter);
70 | }else{
71 | playerLayout.start(DemoApp.mUrl[2],"");
72 | }
73 |
74 | }
75 |
76 | @Override
77 | protected void onDestroy() {
78 | PlayerUtils.release();
79 | super.onDestroy();
80 | }
81 |
82 | @Override
83 | protected void onResume() {
84 | super.onResume();
85 | if(ScreenConvertor.isPlaying()) {
86 | //PlayerUtils.start();
87 | }
88 | }
89 |
90 | @Override
91 | protected void onPause() {
92 | super.onPause();
93 | ScreenConvertor.setPlaying();
94 | PlayerUtils.pause();
95 | }
96 |
97 | @Override
98 | public void onBackPressed() {
99 | if(!ScreenConvertor.onBackPressed(this)){
100 | super.onBackPressed();
101 | }
102 | }
103 |
104 | public T id(int id){
105 | return (T)findViewById(id);
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/video/demo/ScreenConvertor.java:
--------------------------------------------------------------------------------
1 | package com.video.demo;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.pm.ActivityInfo;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.view.Window;
9 | import android.widget.FrameLayout;
10 | import com.uis.lib.simpleplayer.PlayerLayout;
11 | import com.uis.lib.simpleplayer.player.PlayerUtils;
12 | import java.util.Observer;
13 |
14 | /**
15 | * 屏幕视图变换器
16 | * @author uis on 2017/12/1.
17 | */
18 |
19 | public class ScreenConvertor {
20 |
21 | private static boolean isPlaying;
22 | private static Observer sObserver;
23 |
24 | static void deleteObserver(){
25 | sObserver = null;
26 | }
27 |
28 | static void notifyobserver(Object data){
29 | if(sObserver != null){
30 | sObserver.update(null,data);
31 | }
32 | }
33 |
34 | public static void setObserver(Observer observer){
35 | sObserver = observer;
36 | }
37 |
38 | public static void setPlaying(){
39 | isPlaying = PlayerUtils.isPlaying();
40 | }
41 |
42 | public static boolean isPlaying(){
43 | return isPlaying;
44 | }
45 |
46 | /**
47 | * 设置全屏播放
48 | * @param canPlay true:全屏,false:独立页面
49 | * @param layout
50 | */
51 | public static void setFullScreen(boolean canPlay,PlayerLayout layout){
52 | if(layout == null || !(layout.getContext() instanceof Activity)){
53 | return;
54 | }
55 | Activity ac = (Activity)layout.getContext();
56 | ViewGroup out = (ViewGroup)ac.findViewById(R.id.video_outside_id);
57 | boolean isOutSide = out.getChildCount() == 0;
58 | if(canPlay && isOutSide){//全屏播放
59 | layout.controlFullScreen();
60 | }else{//独立页面播放
61 | createFullScreen(ac);
62 | }
63 | }
64 |
65 | public static boolean onBackPressed(Context mc){
66 | return PlayerLayout.onBackPressed(mc) || destroyFullScreen(mc);
67 | }
68 |
69 | public static boolean destroyFullScreen(Context mc){
70 | if(mc!=null && mc instanceof Activity) {
71 | Activity ac = (Activity) mc;
72 | ViewGroup vg = (ViewGroup)ac.findViewById(Window.ID_ANDROID_CONTENT);
73 | ViewGroup out = (ViewGroup)ac.findViewById(R.id.video_outside_id);
74 | View container = vg.findViewById(R.id.video_container_id);
75 | if (container != null && out != null && out.getChildCount()==0) {
76 | PlayerUtils.showActionBar(ac);
77 | vg.removeView(container);
78 | out.addView(container);
79 | notifyobserver(null);
80 | deleteObserver();
81 | container.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
82 | ac.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
83 | return true;
84 | }
85 | }
86 | return false;
87 | }
88 |
89 | static void createFullScreen(Activity ac){
90 | ViewGroup vg = (ViewGroup)ac.findViewById(Window.ID_ANDROID_CONTENT);
91 | ViewGroup out = (ViewGroup)ac.findViewById(R.id.video_outside_id);
92 | final View container = vg.findViewById(R.id.video_container_id);
93 | if(container != null && out != null && out.getChildCount()>0) {
94 | PlayerUtils.hideActionBar(ac);
95 | out.removeView(container);
96 | FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
97 | FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
98 | vg.addView(container,params);
99 | notifyobserver("true");
100 | container.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
101 | @Override
102 | public void onSystemUiVisibilityChange(int visibility) {
103 | if(sObserver!=null){
104 | setViewFullScreen(container);
105 | }
106 | }
107 | });
108 | setViewFullScreen(container);
109 | ac.setRequestedOrientation( ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
110 | }
111 | }
112 |
113 | static void setViewFullScreen(View v){
114 | if(v != null) {
115 | v.setSystemUiVisibility(
116 | View.SYSTEM_UI_FLAG_FULLSCREEN
117 | |View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
118 | );
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/video/demo/VideoAdapter.java:
--------------------------------------------------------------------------------
1 | package com.video.demo;
2 |
3 | import android.support.v4.view.ViewPager;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.text.TextUtils;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 |
10 | import com.uis.lib.simpleplayer.Vlog;
11 | import com.uis.lib.simpleplayer.PlayerLayout;
12 |
13 | /**
14 | * @author uis on 2017/11/17.
15 | */
16 |
17 | public class VideoAdapter extends RecyclerView.Adapter {
18 |
19 | private String[] data;
20 |
21 | public VideoAdapter() {
22 | super();
23 | }
24 |
25 | public void setData(String[] data){
26 | this.data = data;
27 | }
28 |
29 | @Override
30 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
31 | View v;
32 | RecyclerView.ViewHolder vh;
33 | if(viewType==0) {
34 | v = LayoutInflater.from(parent.getContext()).inflate(R.layout.vh_video, parent, false);
35 | vh = new VideoVH(v);
36 | }else{
37 | v = LayoutInflater.from(parent.getContext()).inflate(R.layout.vh_viewpager, parent, false);
38 | vh = new VpVH(v);
39 | }
40 | return vh;
41 | }
42 |
43 | @Override
44 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
45 | if(holder instanceof VideoVH){
46 | ((VideoVH)holder).onViewBind(data[position]);
47 | }else if(holder instanceof VpVH){
48 | ((VpVH)holder).onViewBind();
49 | }
50 | }
51 |
52 | @Override
53 | public void onViewRecycled(RecyclerView.ViewHolder holder) {
54 | if(holder instanceof VideoVH){
55 | ((VideoVH)holder).onViewRecycled();
56 | }
57 | super.onViewRecycled(holder);
58 | }
59 |
60 | @Override
61 | public int getItemViewType(int position) {
62 | String pos = data[position];
63 | return TextUtils.isEmpty(pos)?1:0;
64 | }
65 |
66 | @Override
67 | public int getItemCount() {
68 | return data==null?0:data.length;
69 | }
70 |
71 | static class VpVH extends RecyclerView.ViewHolder{
72 | ViewPager viewPager;
73 | VideoPagerAdapter adapter;
74 |
75 | public VpVH(View itemView) {
76 | super(itemView);
77 | this.viewPager = id(itemView,R.id.viewpager);
78 | }
79 |
80 | public void onViewBind(){
81 | Vlog.e("xx","onViewBind...");
82 | if(adapter == null) {
83 | adapter = new VideoPagerAdapter();
84 | viewPager.setOffscreenPageLimit(7);
85 | viewPager.addOnPageChangeListener(adapter);
86 | viewPager.setAdapter(adapter);
87 | }
88 | }
89 | }
90 |
91 | static class VideoVH extends RecyclerView.ViewHolder{
92 | PlayerLayout player;
93 | String videoUrl;
94 |
95 | public VideoVH(View itemView) {
96 | super(itemView);
97 | player = id(itemView,R.id.player);
98 | }
99 |
100 | public void onViewRecycled(){
101 | Vlog.e("xx","onViewRecycled...");
102 | }
103 |
104 | public void onViewBind(String url){
105 | Vlog.e("xx","onViewBind...");
106 | player.start(url,DemoApp.URL);
107 | }
108 | }
109 |
110 | public static T id(View view,int id){
111 | return (T)view.findViewById(id);
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/video/demo/VideoPagerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.video.demo;
2 |
3 | import android.app.Activity;
4 | import android.content.res.Resources;
5 | import android.support.v4.view.PagerAdapter;
6 | import android.support.v4.view.ViewPager;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.view.Window;
10 |
11 | import com.facebook.drawee.view.SimpleDraweeView;
12 | import com.uis.lib.simpleplayer.OnScreenListener;
13 | import com.uis.lib.simpleplayer.PlayerLayout;
14 | import com.uis.lib.simpleplayer.PlayerStateCallback;
15 | import com.uis.lib.simpleplayer.Vlog;
16 | import com.uis.lib.simpleplayer.player.PlayerComplete;
17 | import com.uis.lib.simpleplayer.player.PlayerUtils;
18 |
19 | import java.util.LinkedList;
20 | import java.util.Observable;
21 | import java.util.Observer;
22 |
23 | /**
24 | * @author uis on 2017/11/22.
25 | */
26 |
27 | public class VideoPagerAdapter extends PagerAdapter implements ViewPager.OnPageChangeListener,Observer{
28 |
29 | private LinkedList mList = new LinkedList<>();
30 | private PlayerLayout mVideo;
31 | private final int WIDTH;
32 | private int currentPos;
33 | private boolean canVisibility;
34 | private View ivClose;
35 | private View vState;
36 |
37 |
38 | public VideoPagerAdapter() {
39 | canVisibility = false;
40 | currentPos = 0;
41 | WIDTH = Resources.getSystem().getDisplayMetrics().widthPixels;
42 | ScreenConvertor.setPlaying();
43 | }
44 |
45 | @Override
46 | public Object instantiateItem(ViewGroup container, final int position) {
47 | View v;
48 | if(position>0) {
49 | if (mList.size() > 0) {
50 | v = mList.pop();
51 | }else {
52 | v = new SimpleDraweeView(container.getContext());
53 | ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(-1, WIDTH);
54 | v.setLayoutParams(params);
55 | }
56 | SimpleDraweeView sdView = (SimpleDraweeView)v;
57 | sdView.setOnClickListener(new View.OnClickListener() {
58 | @Override
59 | public void onClick(View v) {
60 | changeScreen(false);
61 | }
62 | });
63 | sdView.setImageURI(DemoApp.URL);
64 | }else{
65 | if(mVideo == null) {
66 | mVideo = new PlayerLayout(container.getContext());
67 | mVideo.setPlayerStateCallback(new PlayerStateCallback() {
68 | @Override
69 | public void onState(int state) {
70 | //Vlog.a("xx","state = " + state);
71 | if(state == PlayerComplete.STATE_START){
72 | vState.setVisibility(View.GONE);
73 | }else if(state == PlayerComplete.STATE_RESET || state == PlayerComplete.STATE_RELEASE){
74 | if(!canVisibility) {
75 | vState.setVisibility(View.VISIBLE);
76 | }
77 | }
78 | }
79 | });
80 | ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(-1, WIDTH);
81 | mVideo.setLayoutParams(params);
82 | String url = DemoApp.mUrl[2];
83 | mVideo.start(position >= 0 ? url : "", DemoApp.URL);
84 | mVideo.setOnScreenListener(new OnScreenListener() {
85 | @Override
86 | public void onScreen(boolean isFullScreen) {//点击了放大
87 | changeScreen(true);
88 | }
89 | });
90 | Activity ac = (Activity)container.getContext();
91 | ViewGroup vg = (ViewGroup)ac.findViewById(Window.ID_ANDROID_CONTENT);
92 | final View cv = vg.findViewById(R.id.video_container_id);
93 | ivClose = cv.findViewById(R.id.video_close_id);
94 | ivClose.setOnClickListener(new View.OnClickListener() {
95 | @Override
96 | public void onClick(View v) {
97 | ScreenConvertor.destroyFullScreen(mVideo.getContext());
98 | }
99 | });
100 | vState = cv.findViewById(R.id.v_state);
101 | }
102 | v = mVideo;
103 | }
104 | container.addView(v);
105 | return v;
106 | }
107 |
108 | @Override
109 | public void destroyItem(ViewGroup container, int position, Object object) {
110 | View v = (View)object;
111 | container.removeView(v);
112 | if(position!=0) {
113 | mList.push(v);
114 | }
115 | }
116 |
117 | @Override
118 | public int getCount() {
119 | return DemoApp.mUrl.length;
120 | }
121 |
122 | @Override
123 | public boolean isViewFromObject(View view, Object object) {
124 | return view == object;
125 | }
126 |
127 | @Override
128 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
129 |
130 | }
131 |
132 | @Override
133 | public void onPageSelected(int position) {
134 | if(currentPos == 0){
135 | ScreenConvertor.setPlaying();
136 | }
137 | if(position == 0 && ScreenConvertor.isPlaying()){
138 | PlayerUtils.start();
139 | }else {
140 | PlayerUtils.pause();
141 | }
142 | currentPos = position;
143 | if(ivClose!=null) {
144 | ivClose.setVisibility((canVisibility && position == 0) ? View.VISIBLE : View.GONE);
145 | }
146 | }
147 |
148 | @Override
149 | public void onPageScrollStateChanged(int state) {
150 |
151 | }
152 |
153 | @Override
154 | public void update(Observable observable, Object data) {
155 | if(data == null){
156 | ivClose.setVisibility(View.GONE);
157 | }else if(data != null && currentPos == 0){
158 | ivClose.setVisibility(View.VISIBLE);
159 | }
160 | canVisibility = (data!=null);
161 | }
162 |
163 | void changeScreen(boolean canPlay){
164 | ScreenConvertor.setObserver(this);
165 | ScreenConvertor.setFullScreen(canPlay,mVideo);
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
15 |
16 |
21 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/player_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
12 |
20 |
27 |
34 |
44 |
52 |
61 |
69 |
70 |
78 |
86 |
97 |
105 |
112 |
121 |
128 |
136 |
137 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/vh_video.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/vh_viewpager.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
14 |
20 |
21 |
30 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/demo/src/main/res/raw/intro.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luiing/SimplePlayer/48af00a01bdf27e962c8214912c4b23629c5235a/demo/src/main/res/raw/intro.mp4
--------------------------------------------------------------------------------
/demo/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | PlayerDemo
3 |
4 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luiing/SimplePlayer/48af00a01bdf27e962c8214912c4b23629c5235a/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Nov 27 10:39:00 CST 2017
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.1-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 |
--------------------------------------------------------------------------------
/lib-simpleplayer/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/lib-simpleplayer/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 | apply plugin: 'com.jfrog.bintray'
4 | def siteUrl = 'https://github.com/luiing/SimplePlayer'
5 | def gitUrl = 'https://github.com/luiing/SimplePlayer.git'
6 | version = "0.2.0"
7 | android {
8 | compileSdkVersion compileVer
9 | buildToolsVersion buildVer
10 | defaultConfig {
11 | minSdkVersion minVer
12 | targetSdkVersion targetVer
13 | versionCode 1
14 | versionName version
15 |
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 |
25 | }
26 |
27 | dependencies {
28 | compile fileTree(dir: 'libs', include: ['*.jar'])
29 | compile 'com.android.support:appcompat-v7:'+supportVer
30 | compile 'com.facebook.fresco:fresco:1.5.0'
31 | }
32 |
33 | install {
34 | repositories.mavenInstaller {
35 | // This generates POM.xml with proper parameters
36 | pom {
37 | project {
38 | packaging 'aar'
39 | name 'SimplePlayer'
40 | description 'This program is simple media player.'
41 | // #CONFIG# // project title
42 | url siteUrl
43 | // Set your license
44 | licenses {
45 | license {
46 | name 'The Apache Software License, Version 2.0'
47 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
48 | }
49 | }
50 | developers {
51 | developer {
52 | id "sweet"//org unique id
53 | // #CONFIG# // your user id (you can write your nickname)
54 | name "luiing"//current user id
55 | // #CONFIG# // your user name
56 | email ""
57 | // #CONFIG# // your email
58 | }
59 | }
60 | scm {
61 | connection gitUrl
62 | developerConnection gitUrl
63 | url siteUrl
64 | }
65 | }
66 | }
67 | }
68 | }
69 |
70 | task sourcesJar(type: Jar) {
71 | from android.sourceSets.main.java.srcDirs
72 | classifier = 'sources'
73 | }
74 |
75 | task javadoc(type: Javadoc) {
76 | options.encoding = "UTF-8"
77 | source = android.sourceSets.main.java.srcDirs
78 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
79 | }
80 |
81 | task javadocJar(type: Jar, dependsOn: javadoc) {
82 | classifier = 'javadoc'
83 | from javadoc.destinationDir
84 | }
85 |
86 | artifacts {
87 | archives javadocJar
88 | archives sourcesJar
89 | }
90 |
91 | Properties properties = new Properties()
92 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
93 | group = properties.getProperty("bintray.group")
94 | def bid = properties.getProperty("bintray.id")
95 | def bname = properties.getProperty("bintray.name")
96 | def blib = properties.getProperty("bintray.lib")
97 | bintray {
98 | user = bname
99 | key = properties.getProperty("bintray.apikey")
100 | configurations = ['archives']
101 | pkg {
102 | userOrg = bid
103 | repo = "maven"
104 | name = blib
105 | // #CONFIG# project name in jcenter
106 | websiteUrl = siteUrl
107 | vcsUrl = gitUrl
108 | licenses = ["Apache-2.0"]
109 | publish = true
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/lib-simpleplayer/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 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/java/com/uis/lib/simpleplayer/OnScreenListener.java:
--------------------------------------------------------------------------------
1 | package com.uis.lib.simpleplayer;
2 |
3 | /**
4 | * @author uis on 2017/11/29.
5 | */
6 |
7 | public interface OnScreenListener {
8 | void onScreen(boolean isFullScreen);
9 | }
10 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/java/com/uis/lib/simpleplayer/PlayerLayout.java:
--------------------------------------------------------------------------------
1 | package com.uis.lib.simpleplayer;
2 |
3 | import android.annotation.TargetApi;
4 | import android.app.Activity;
5 | import android.content.BroadcastReceiver;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.content.IntentFilter;
9 | import android.content.pm.ActivityInfo;
10 | import android.graphics.Color;
11 | import android.net.ConnectivityManager;
12 | import android.net.wifi.WifiManager;
13 | import android.support.annotation.NonNull;
14 | import android.support.annotation.Nullable;
15 | import android.text.TextUtils;
16 | import android.util.AttributeSet;
17 | import android.view.View;
18 | import android.view.ViewGroup;
19 | import android.view.Window;
20 | import android.widget.FrameLayout;
21 | import android.widget.ImageView;
22 | import android.widget.LinearLayout;
23 | import android.widget.ProgressBar;
24 | import android.widget.SeekBar;
25 | import android.widget.TextView;
26 |
27 | import com.facebook.drawee.drawable.ScalingUtils;
28 | import com.facebook.drawee.generic.GenericDraweeHierarchy;
29 | import com.facebook.drawee.view.SimpleDraweeView;
30 | import com.uis.lib.simpleplayer.player.BasePlayerLayout;
31 | import com.uis.lib.simpleplayer.player.PlayerCallback;
32 | import com.uis.lib.simpleplayer.player.PlayerComplete;
33 | import com.uis.lib.simpleplayer.player.PlayerListener;
34 | import com.uis.lib.simpleplayer.player.PlayerUtils;
35 |
36 | /**
37 | * 播放控制器界面
38 | * @author uis on 2017/11/21.
39 | */
40 |
41 | public class PlayerLayout extends BasePlayerLayout implements View.OnClickListener{
42 | private final static String TAG = "PlayerLayout";
43 | private FrameLayout frameLayout;
44 | private FrameLayout playerFrame;
45 | private SimpleDraweeView thumb;
46 | private ImageView ivPlay;
47 | private ImageView ivPlaySmall;
48 | private ImageView ivPause;
49 | private ImageView ivBack;
50 | private ImageView ivClose;
51 | private ProgressBar pbarLoading;
52 | private ProgressBar pbarRate;
53 | private LinearLayout llRate;
54 | private LinearLayout llPlay;
55 | private TextView tvPlayTime;
56 | private TextView tvTotalTime;
57 | private ImageView ivFullscreen;
58 | private SeekBar sbarRate;
59 | private boolean isInit = false;
60 | private boolean isSeeking = false;
61 | private boolean isVideoLand;
62 | private OnScreenListener onScreenListener;
63 | private PlayerStateCallback stateCallback;
64 | private int percentTime;
65 | private static final int MAX_PERCENT = 980;
66 | private NetChangeReceiver mReceiver;
67 |
68 | public PlayerLayout(@NonNull Context context) {
69 | this(context,null);
70 | }
71 |
72 | public PlayerLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
73 | this(context, attrs,0);
74 | }
75 |
76 | public PlayerLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
77 | super(context, attrs, defStyleAttr);
78 | }
79 |
80 | @TargetApi(21)
81 | public PlayerLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
82 | super(context, attrs, defStyleAttr, defStyleRes);
83 | }
84 |
85 | interface OnNetChanged{
86 | void onChanged();
87 | }
88 |
89 | static class NetChangeReceiver extends BroadcastReceiver {
90 | OnNetChanged mOnNetChanged;
91 |
92 | @Override
93 | public void onReceive(Context context, Intent intent) {
94 | if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) {
95 |
96 | } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(intent.getAction())) {
97 |
98 | } else if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
99 |
100 | }else{
101 | return;
102 | }
103 | if(mOnNetChanged != null){
104 | mOnNetChanged.onChanged();
105 | }
106 | }
107 |
108 | public void setOnNetChanged(OnNetChanged changed){
109 | mOnNetChanged = changed;
110 | }
111 | }
112 |
113 | @Override
114 | protected void onAttachedToWindow() {
115 | super.onAttachedToWindow();
116 | registerNetChanged();
117 | }
118 |
119 | @Override
120 | protected void onDetachedFromWindow() {
121 | super.onDetachedFromWindow();
122 | unregisterNetChanged();
123 | }
124 |
125 | private void registerNetChanged(){
126 | IntentFilter filter = new IntentFilter();
127 | filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
128 | filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
129 | filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
130 | if(mReceiver == null){
131 | mReceiver = new NetChangeReceiver();
132 | mReceiver.setOnNetChanged(new OnNetChanged() {
133 | @Override
134 | public void onChanged() {
135 | if(isRelease() && !isLoading()){
136 | checkWifi();
137 | }
138 | }
139 | });
140 | }
141 | if(mReceiver != null && getContext()!=null) {
142 | getContext().registerReceiver(mReceiver, filter);
143 | }
144 | }
145 |
146 | private void unregisterNetChanged(){
147 | if(mReceiver != null && getContext()!=null) {
148 | getContext().unregisterReceiver(mReceiver);
149 | }
150 | }
151 |
152 | @Override
153 | public void init(){
154 | int layoutId = mATTR.getResourceId(R.styleable.PlayerLayout_playLayout,R.layout.video_player_layout);
155 | mATTR.recycle();
156 | setBackgroundColor(Color.BLACK);
157 | setClickable(true);
158 | inflate(getContext(),layoutId,this);
159 | frameLayout = id(R.id.player_id_frame);
160 | playerFrame = id(R.id.player_id_player);
161 | llPlay = id(R.id.player_id_ll_play);
162 | ivPlaySmall = id(R.id.player_id_iv_play_s);
163 | thumb = id(R.id.player_id_thumb);
164 | ivPlay = id(R.id.player_id_iv_play);
165 | ivPause = id(R.id.player_id_iv_pause);
166 | pbarLoading = id(R.id.player_id_pbar_loading);
167 | pbarRate = id(R.id.player_id_pbar_rate);
168 | llRate = id(R.id.player_id_ll_rate);
169 | tvPlayTime = id(R.id.player_id_tv_play_time);
170 | tvTotalTime = id(R.id.player_id_tv_total_time);
171 | ivFullscreen = id(R.id.player_id_iv_fullscreen);
172 | sbarRate = id(R.id.player_id_seekBar);
173 | ivBack = id(R.id.player_id_iv_back);
174 | ivClose = id(R.id.player_id_iv_close);
175 | pbarRate.setMax(MaxRate);
176 | sbarRate.setMax(MaxRate);
177 | frameLayout.setOnClickListener(this);
178 | ivPlay.setOnClickListener(this);
179 | ivPlaySmall.setOnClickListener(this);
180 | ivPause.setOnClickListener(this);
181 | ivFullscreen.setOnClickListener(this);
182 | ivBack.setOnClickListener(this);
183 | //ivClose.setOnClickListener(this);
184 | boolean isEdit = isInEditMode();
185 | llRate.setVisibility(isEdit ? VISIBLE:GONE);
186 | pbarRate.setVisibility(isEdit ? VISIBLE:GONE);
187 | ivPlay.setVisibility(isEdit ? VISIBLE:GONE);
188 | llPlay.setVisibility(isEdit ? VISIBLE:GONE);
189 | setPlaceHolderBackground(Color.WHITE);
190 | setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() {
191 | @Override
192 | public void onSystemUiVisibilityChange(int visibility) {
193 | if(isFullScreen() && visibility != SYSTEM_UI_FLAG_FULLSCREEN){
194 | setUiFullScreen();
195 | }
196 | }
197 | });
198 | sbarRate.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
199 | @Override
200 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
201 | if(fromUser && tvPlayTime != null && totalTime>0){
202 | int timeTxt = (int)PlayerUtils.getRate(totalTime,progress,MaxRate);
203 | tvPlayTime.setText(PlayerUtils.getTime(timeTxt));
204 | }
205 | }
206 |
207 | @Override
208 | public void onStartTrackingTouch(SeekBar seekBar) {
209 | isSeeking = true;
210 | }
211 |
212 | @Override
213 | public void onStopTrackingTouch(SeekBar seekBar) {
214 | isSeeking = false;
215 | if(isInit || isFullScreen()) {
216 | int seekTime = totalTime / 1000 * seekBar.getProgress();
217 | seekTo(seekTime);
218 | }else{
219 | seekBar.setProgress(0);
220 | }
221 | }
222 | });
223 |
224 | mComplete = new PlayerComplete() {
225 |
226 | @Override
227 | public void onChanged() {
228 | if(!isFullScreen() && hasFullScreen()){
229 | setHasFullScreen(false);
230 | createPlayer(false);
231 | playerStateInit();
232 | displayUi();
233 | }
234 | }
235 |
236 | @Override
237 | public void onComplete(int state) {
238 | switch (state){
239 | case PlayerComplete.STATE_START:
240 |
241 | break;
242 | case PlayerComplete.STATE_PAUSE:
243 | break;
244 | case PlayerComplete.STATE_PREPARE:
245 | displayUi();
246 | break;
247 | case PlayerComplete.STATE_PREPARING:
248 | initState(true);
249 | showLoading();
250 | break;
251 | case PlayerComplete.STATE_RELEASE:
252 | isInit = false;
253 | case PlayerComplete.STATE_RESET:
254 |
255 | percentTime = 0;
256 | totalTime = 0;
257 | initState(false);
258 | break;
259 | }
260 | if(stateCallback != null){
261 | stateCallback.onState(state);
262 | }
263 | }
264 | };
265 |
266 | mCallback = new PlayerCallback() {
267 | @Override
268 | public void onPrepared(PlayerListener vp) {
269 | totalTime = vp.getDuration();
270 | pbarRate.setVisibility(VISIBLE);
271 | initState(true);
272 | resize();
273 | }
274 |
275 | @Override
276 | public void onBufferingUpdate(PlayerListener vp, int percent) {
277 | if(percent>98) {
278 | percent = 98;
279 | }
280 | percentTime = 10*percent;
281 | int pb = pbarRate.getSecondaryProgress();
282 | if(percentTime > pb) {
283 | pbarRate.setSecondaryProgress(percentTime);
284 | sbarRate.setSecondaryProgress(percentTime);
285 | }
286 | }
287 |
288 | @Override
289 | public void onCompletion(PlayerListener vp) {
290 | if(isFullScreen()) {
291 | controlFullScreen();
292 | }
293 | initState(false);
294 | if(stateCallback != null){
295 | stateCallback.onCompletion();
296 | }
297 | }
298 |
299 | @Override
300 | public void onError(PlayerListener vp, int what, int extra) {
301 | PlayerUtils.toast(getContext(), "视频播放失败,请检查网络");
302 | }
303 |
304 | @Override
305 | public void onSeekComplete(PlayerListener vp) {
306 |
307 | }
308 |
309 | @Override
310 | public void onProgress(int current, int total) {
311 | if(current>0 && thumb.getVisibility() == VISIBLE){
312 | thumbVisibility(false);
313 | }
314 | if(totalTime == 0){
315 | totalTime = total;
316 | }
317 | if(current != currentTime){
318 | hideLoading();
319 | }else{
320 | showLoading();
321 | }
322 | currentTime = current;
323 | int rate = total==0 ? 0 : (int)PlayerUtils.getRate(MaxRate,current,total);
324 | pbarRate.setProgress(rate);
325 | if(!isSeeking) {
326 | sbarRate.setProgress(rate);
327 | tvPlayTime.setText(PlayerUtils.getTime(current));
328 | }
329 | tvTotalTime.setText(PlayerUtils.getTime(total));
330 | if(isFullScreen() && percentTime == MAX_PERCENT){
331 | pbarRate.setSecondaryProgress(percentTime);
332 | sbarRate.setSecondaryProgress(percentTime);
333 | }
334 | }
335 |
336 | @Override
337 | public void onVideoSizeChanged(PlayerListener vp, int width, int height) {
338 | isVideoLand = width > height;
339 | resize();
340 | }
341 | };
342 | }
343 |
344 | private void setPlayGone(){
345 | ivPlay.setVisibility(GONE);
346 | llPlay.setVisibility(GONE);
347 | }
348 |
349 | private void checkWifi(){
350 | if(!PlayerUtils.isWifiConnected(getContext())){
351 | llPlay.setVisibility(VISIBLE);
352 | ivPlay.setVisibility(GONE);
353 | }else{
354 | ivPlay.setVisibility(VISIBLE);
355 | llPlay.setVisibility(GONE);
356 | }
357 | }
358 |
359 | public void setOnScreenListener(OnScreenListener onScreenListener) {
360 | this.onScreenListener = onScreenListener;
361 | }
362 |
363 | public void setPlayerStateCallback(PlayerStateCallback callback){
364 | this.stateCallback = callback;
365 | }
366 |
367 | @Override
368 | public void onClick(View v) {
369 | int id = v.getId();
370 | if(id == R.id.player_id_frame){
371 | displayUi();
372 | }else if(id == R.id.player_id_iv_close || id == R.id.player_id_iv_back){
373 | controlFullScreen();
374 | }else if(id == R.id.player_id_iv_fullscreen){
375 | if(onScreenListener!=null){
376 | onScreenListener.onScreen(isFullScreen());
377 | }else {
378 | controlFullScreen();
379 | }
380 | }else if(id == R.id.player_id_iv_play || id == R.id.player_id_iv_play_s){
381 | if(!PlayerUtils.isConnected(getContext()) && isRelease() && !isVideoFile()) {
382 | PlayerUtils.toast(getContext(), "当前无网络连接");
383 | }else{
384 | playState();
385 | }
386 | }else if(id == R.id.player_id_iv_pause){
387 | playState();
388 | }
389 | }
390 |
391 | private boolean isVideoFile(){
392 | String path = getVideoUrl();
393 | return !TextUtils.isEmpty(path)&&path.startsWith("/");
394 | }
395 |
396 | private void initState(boolean isStart){
397 | if(isStart){
398 | ivPlay.setVisibility(GONE);
399 | ivPause.setVisibility(GONE);
400 | llPlay.setVisibility(GONE);
401 | }else{
402 | pbarLoading.setVisibility(GONE);
403 | pbarRate.setVisibility(GONE);
404 | llRate.setVisibility(GONE);
405 | thumbVisibility(true);
406 | boolean isCurrent = false;
407 | if(PlayerUtils.isPlaying()){
408 | if(PlayerUtils.isPlaying(getVideoUrl())) {//play current videoUrl
409 | isCurrent = true;
410 | }else{//play another videoUrl
411 | }
412 | }
413 | if(isCurrent){
414 | setPlayGone();
415 | ivPause.setVisibility(VISIBLE);
416 | }else {
417 | checkWifi();
418 | ivPause.setVisibility(GONE);
419 | }
420 | }
421 | }
422 |
423 | private void playState(){
424 | playerStateInit();
425 | if(!isPlaying()){
426 | prepare();
427 | isInit = true;
428 | if(stateCallback != null){
429 | stateCallback.onPlay(isRelease());
430 | }
431 | }else{
432 | pause();
433 | if(stateCallback != null){
434 | stateCallback.onPause();
435 | }
436 | }
437 | playerStateUi();
438 | }
439 |
440 | private void playerStateInit(){
441 | createPlayer(isFullScreen());
442 | setDataSource();
443 | }
444 |
445 | private void playerStateUi(){
446 | if(llRate.getVisibility() == VISIBLE) {
447 | boolean isPlaying = isPlaying();
448 | if (isPlaying) {
449 | ivPlay.setVisibility(GONE);
450 | ivPause.setVisibility(VISIBLE);
451 | } else {
452 | ivPlay.setVisibility(VISIBLE);
453 | ivPause.setVisibility(GONE);
454 | }
455 | }
456 | }
457 |
458 | public void controlFullScreen(){
459 | if(isFullScreen()){
460 | destroyFullScreen();
461 | }else{
462 | setHasFullScreen(true);
463 | createFullScreen(isVideoLand);
464 | }
465 | }
466 |
467 | private boolean isLoading(){
468 | return pbarLoading!=null && VISIBLE == pbarLoading.getVisibility();
469 | }
470 |
471 | private void showLoading(){
472 | if(GONE == pbarLoading.getVisibility()) {
473 | pbarLoading.setVisibility(VISIBLE);
474 | }
475 | }
476 |
477 | private void hideLoading() {
478 | if(VISIBLE == pbarLoading.getVisibility()) {
479 | pbarLoading.setVisibility(GONE);
480 | }
481 | }
482 |
483 | private void displayUi(){
484 | stopTimer();
485 | onCounter(true);
486 | }
487 |
488 | @Override
489 | protected void onCounter(boolean userStop) {
490 | if(llRate == null || isRelease() || totalTime<=0){
491 | return;
492 | }
493 | int vis = llRate.getVisibility();
494 | if(vis == VISIBLE){
495 | ivPlay.setVisibility(GONE);
496 | ivPause.setVisibility(GONE);
497 | llRate.setVisibility(GONE);
498 | pbarRate.setVisibility(VISIBLE);
499 | if(isFullScreen()){
500 | ivBack.setVisibility(GONE);
501 | }
502 | }else{
503 | startTimer();
504 | pbarRate.setVisibility(GONE);
505 | llRate.setVisibility(VISIBLE);
506 | playerStateUi();
507 | if(isFullScreen()){
508 | ivBack.setVisibility(VISIBLE);
509 | }
510 | }
511 | }
512 |
513 | public void setPlaceHolderBackground(int color){
514 | if(thumb != null){
515 | thumb.setBackgroundColor(color);
516 | }
517 | }
518 |
519 | public void setPlaceHolderImage(int resourceId){
520 | this.setPlaceHolderImage(resourceId,ScalingUtils.ScaleType.CENTER_INSIDE);
521 | }
522 |
523 | public void setPlaceHolderImage(int resourceId,ScalingUtils.ScaleType scaleType){
524 | if(thumb!=null){
525 | GenericDraweeHierarchy gdh = thumb.getHierarchy();
526 | gdh.setPlaceholderImage(resourceId, scaleType);
527 | }
528 | }
529 |
530 | public void start(String videoPath,String thumbPath){
531 | if(!TextUtils.isEmpty(thumbPath)) {
532 | setThumbUrl(thumbPath);
533 | thumb.setImageURI(thumbPath);
534 | thumbVisibility(true);
535 | }
536 | if(TextUtils.isEmpty(videoPath)){
537 | setPlayGone();
538 | return;
539 | }
540 | setVideoUrl(videoPath);
541 | if(isFullScreen()) {
542 | playerStateInit();
543 | displayUi();
544 | }else{
545 | initState(false);
546 | }
547 | }
548 |
549 | private void thumbVisibility(boolean isVisibility){
550 | if(!isFullScreen() && isVisibility){
551 | thumb.setVisibility(VISIBLE);
552 | }else{
553 | thumb.setVisibility(GONE);
554 | }
555 | }
556 |
557 | private void removePlayer(){
558 | if(!isFullScreen()){
559 | createPlayerView(false);
560 | }
561 | }
562 |
563 | private void createPlayer(boolean isFull){
564 | if(playerFrame.getChildCount() == 0) {
565 | playerFrame.addView(createPlayerView(isFull));
566 | resize();
567 | }
568 | if(isFull){
569 | ivBack.setVisibility(VISIBLE);
570 | ivFullscreen.setImageResource(R.mipmap.fullscreen_exit);
571 | }else{
572 | ivBack.setVisibility(GONE);
573 | ivFullscreen.setImageResource(R.mipmap.fullscreen_start);
574 | }
575 | }
576 |
577 | void setUiFullScreen(){
578 | setUiFullScreen(this);
579 | }
580 |
581 | void setUiFullScreen(View v){
582 | if(v != null) {
583 | v.setSystemUiVisibility(
584 | SYSTEM_UI_FLAG_FULLSCREEN
585 | |SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
586 | );
587 | }
588 | }
589 |
590 | void createFullScreen(boolean isLand){
591 | Activity ac = (Activity)getContext();
592 | ViewGroup vg = (ViewGroup) ac.findViewById(Window.ID_ANDROID_CONTENT);
593 | View view = vg.findViewById(R.id.video_fullscreen_id);
594 | if(view == null) {
595 | PlayerUtils.hideActionBar(ac);
596 | FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
597 | FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
598 | PlayerLayout frame = new PlayerLayout(ac);
599 | frame.setId(R.id.video_fullscreen_id);
600 | vg.addView(frame,params);
601 | frame.createPlayer(true);
602 | frame.totalTime = totalTime;
603 | frame.percentTime = percentTime;
604 | frame.start(getVideoUrl(),getThumbUrl());
605 | view = frame;
606 | }
607 | setUiFullScreen(view);
608 | ac.setRequestedOrientation(isLand ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
609 | }
610 |
611 | void destroyFullScreen(){
612 | Activity ac = (Activity)getContext();
613 | ViewGroup vg = (ViewGroup)ac.findViewById(Window.ID_ANDROID_CONTENT);
614 | View video = vg.findViewById(R.id.video_fullscreen_id);
615 | if(video != null) {
616 | vg.removeView(video);
617 | PlayerUtils.showActionBar(ac);
618 | video.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE );
619 | ac.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
620 | if(video instanceof PlayerLayout){
621 | ((PlayerLayout)video).onChanged();
622 | }
623 | }
624 | }
625 |
626 | public static boolean onBackPressed(Context mc){
627 | PlayerLayout playerLayout = getFullScreen(mc);
628 | if(playerLayout!=null && playerLayout.isFullScreen()){
629 | playerLayout.controlFullScreen();
630 | return true;
631 | }
632 | return false;
633 | }
634 |
635 | static PlayerLayout getFullScreen(Context mc){
636 | if(mc!=null && mc instanceof Activity) {
637 | Activity ac = (Activity) mc;
638 | ViewGroup vg = (ViewGroup)ac.findViewById(Window.ID_ANDROID_CONTENT);
639 | View video = vg.findViewById(R.id.video_fullscreen_id);
640 | if(video != null){
641 | return (PlayerLayout)video;
642 | }
643 | }
644 | return null;
645 | }
646 | }
647 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/java/com/uis/lib/simpleplayer/PlayerStateCallback.java:
--------------------------------------------------------------------------------
1 | package com.uis.lib.simpleplayer;
2 |
3 | /**
4 | * 播放状态回调
5 | * @author uis on 2017/12/5.
6 | */
7 |
8 | public abstract class PlayerStateCallback {
9 | public void onPlay(boolean inInit){}
10 | public void onPause(){}
11 | public void onCompletion(){}
12 | public void onState(int state){}
13 | }
14 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/java/com/uis/lib/simpleplayer/Vlog.java:
--------------------------------------------------------------------------------
1 | package com.uis.lib.simpleplayer;
2 |
3 | import android.util.Log;
4 |
5 | /**
6 | * Created by lhb on 2017/4/25.
7 | */
8 |
9 | public class Vlog {
10 |
11 | private static boolean debug = false;
12 |
13 | public static void enableDebug(){
14 | debug = true;
15 | }
16 |
17 | public static void disableDebug(){
18 | debug = false;
19 | }
20 |
21 | public static void e(String tag,Object log){
22 | if(debug) {
23 | Log.e(tag, getMessage(log,false));
24 | }
25 | }
26 |
27 | public static void i(String tag,Object log){
28 | if(debug) {
29 | Log.i(tag, getMessage(log,false));
30 | }
31 | }
32 |
33 | public static void a(String tag,Object log){
34 | if(debug) {
35 | Log.w(tag, getMessage(log,true));
36 | }
37 | }
38 |
39 | static String getMessage(Object log,boolean isAll){
40 | StackTraceElement[] stacks = Thread.currentThread().getStackTrace();
41 | StringBuilder builder = new StringBuilder();
42 | StackTraceElement stack = stacks[4];
43 | builder.append(stack.getFileName())
44 | .append("(")
45 | .append(stack.getLineNumber())
46 | .append(")")
47 | .append(stack.getMethodName())
48 | .append(":")
49 | .append(log)
50 | .append("\n");
51 | if(isAll) {
52 | for (StackTraceElement e : stacks) {
53 | builder.append(e.getFileName())
54 | .append("(")
55 | .append(e.getLineNumber())
56 | .append(")")
57 | .append(e.getMethodName())
58 | .append("\n");
59 | }
60 | }
61 | return builder.toString();
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/java/com/uis/lib/simpleplayer/bitmap/OnBitmapListener.java:
--------------------------------------------------------------------------------
1 | package com.uis.lib.simpleplayer.bitmap;
2 |
3 | import android.graphics.Bitmap;
4 |
5 | /**
6 | * @author uis on 2017/11/21.
7 | */
8 |
9 | public interface OnBitmapListener {
10 | void onBitmap(Bitmap bitmap);
11 | }
12 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/java/com/uis/lib/simpleplayer/bitmap/PlayerBitmap.java:
--------------------------------------------------------------------------------
1 | package com.uis.lib.simpleplayer.bitmap;
2 |
3 | import android.graphics.Bitmap;
4 | import android.media.MediaMetadataRetriever;
5 | import android.os.AsyncTask;
6 | import android.os.Build;
7 | import android.support.v4.util.ArrayMap;
8 |
9 | /**
10 | * @author uis on 2017/11/21.
11 | */
12 |
13 | public class PlayerBitmap {
14 |
15 | public static void createBitmapAsync(String url,long time,OnBitmapListener call){
16 | AsyncTask task = new BitmapTask();
17 | task.execute(url,time,call);
18 | }
19 |
20 | public static Bitmap createBitmap(String url, long time){
21 | Bitmap bitmap = null;
22 | MediaMetadataRetriever retriever = new MediaMetadataRetriever();
23 | try {
24 | if (Build.VERSION.SDK_INT >= 14) {
25 | retriever.setDataSource(url, new ArrayMap());
26 | }else {
27 | retriever.setDataSource(url);
28 | }
29 | bitmap = retriever.getFrameAtTime(time);
30 | }catch (Exception ex) {
31 | ex.printStackTrace();
32 | } finally {
33 | try {
34 | retriever.release();
35 | }catch (Exception ex) {
36 | ex.printStackTrace();
37 | }
38 | }
39 | return bitmap;
40 | }
41 |
42 | static class BitmapTask extends AsyncTask{
43 |
44 | static class BitmapData{
45 | Bitmap bitmap;
46 | OnBitmapListener call;
47 | }
48 |
49 | @Override
50 | protected Object doInBackground(Object[] objects) {
51 | if(objects!=null && objects.length==3){
52 | String url = String.valueOf(objects[0]);
53 | long time = (long)objects[1];
54 | BitmapData data = new BitmapData();
55 | data.call = (OnBitmapListener)objects[2];
56 | data.bitmap = createBitmap(url,time);
57 | return data;
58 | }
59 | return null;
60 | }
61 |
62 | @Override
63 | protected void onPostExecute(Object o) {
64 | if(o!=null && o instanceof BitmapData){
65 | BitmapData data = (BitmapData)o;
66 | data.call.onBitmap(data.bitmap);
67 | }
68 | }
69 | };
70 | }
71 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/java/com/uis/lib/simpleplayer/player/BasePlayerLayout.java:
--------------------------------------------------------------------------------
1 | package com.uis.lib.simpleplayer.player;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.support.annotation.NonNull;
7 | import android.support.annotation.Nullable;
8 | import android.util.AttributeSet;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.widget.FrameLayout;
12 | import android.widget.RelativeLayout;
13 |
14 | import com.uis.lib.simpleplayer.R;
15 |
16 | /**
17 | * @author uis on 2017/11/25.
18 | */
19 |
20 | public abstract class BasePlayerLayout extends RelativeLayout {
21 |
22 | public final static int MaxRate = 1000;
23 | public static int sTimerMills = 3500;
24 | protected PlayerView player;
25 | protected PlayerComplete mComplete;
26 | protected PlayerCallback mCallback;
27 | protected int totalTime=0;
28 | protected int currentTime = 0;
29 |
30 | private String mUrl;
31 | private String thumbUrl;
32 | private boolean isFullScreen = false;
33 | private boolean hasFullscreen = false;
34 | private PlayerCounter mCounter;
35 |
36 | protected TypedArray mATTR;
37 |
38 | public BasePlayerLayout(@NonNull Context context) {
39 | this(context,null);
40 | }
41 |
42 | public BasePlayerLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
43 | this(context, attrs,0);
44 | }
45 |
46 | public BasePlayerLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
47 | super(context, attrs, defStyleAttr);
48 | mATTR = context.obtainStyledAttributes(attrs, R.styleable.PlayerLayout, defStyleAttr,0);
49 | innerInit();
50 | }
51 |
52 | @TargetApi(21)
53 | public BasePlayerLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
54 | super(context, attrs, defStyleAttr, defStyleRes);
55 | mATTR = context.obtainStyledAttributes(attrs, R.styleable.PlayerLayout, defStyleAttr,defStyleRes);
56 | innerInit();
57 | }
58 |
59 | private void innerInit(){
60 | mCounter = PlayerCounter.createCounter();
61 | init();
62 | }
63 |
64 | private void initPlayer(){
65 | if(player == null){
66 | player = PlayerUtils.initPlayer(getContext().getApplicationContext());
67 | }
68 | }
69 |
70 | protected void stopTimer(){
71 | mCounter.stopTimer();
72 | }
73 |
74 | protected void startTimer(){
75 | mCounter.startTimer(true,false,sTimerMills,new Runnable() {
76 | @Override
77 | public void run() {
78 | onCounter(false);
79 | }
80 | });
81 | }
82 |
83 | protected abstract void init();
84 |
85 | protected void onCounter(boolean userStop){
86 |
87 | }
88 |
89 | protected PlayerView createPlayerView(boolean isFull){
90 | initPlayer();
91 | setFullScreen(isFull);
92 | if(player.getParent()!=null && player.getParent() instanceof ViewGroup){
93 | ViewGroup vg = (ViewGroup)player.getParent();
94 | vg.removeView(player);
95 | }
96 | return player;
97 | }
98 |
99 | public T id(int resId){
100 | return (T)findViewById(resId);
101 | }
102 |
103 | protected void seekTo(int seek){
104 | if(player!=null) {
105 | player.seekTo(seek);
106 | }
107 | }
108 |
109 | protected void prepare(){
110 | if(player!=null) {
111 | player.prepare();
112 | }
113 | }
114 |
115 | protected void pause(){
116 | if(player!=null) {
117 | player.pause();
118 | }
119 | }
120 |
121 | public boolean isPlaying(){
122 | return player!=null && player.isPlaying();
123 | }
124 |
125 | public boolean isRelease(){
126 | return player==null || player.isRelease();
127 | }
128 |
129 | protected void setFullScreen(boolean isFull){
130 | isFullScreen = isFull;
131 | if(player!=null) {
132 | player.setFullScreen(isFull);
133 | }
134 | }
135 |
136 | public boolean isFullScreen(){
137 | return isFullScreen;
138 | }
139 |
140 | protected void setDataSource(){
141 | if(player!=null) {
142 | player.setDataSource(getContext().hashCode(),mUrl, mCallback,isFullScreen ? null : mComplete);
143 | }
144 | }
145 |
146 | protected void resize(){
147 | PlayerCounter.mHandler.postDelayed(new InnerResize(player),32);
148 | }
149 |
150 | static class InnerResize implements Runnable{
151 | PlayerView playerView;
152 |
153 | public InnerResize(PlayerView playerView) {
154 | this.playerView = playerView;
155 | }
156 |
157 | @Override
158 | public void run() {
159 | if (playerView != null) {
160 | playerView.resize();
161 | }
162 | }
163 | }
164 |
165 | protected void onChanged(){
166 | if(player!=null){
167 | player.onChanged();
168 | }
169 | }
170 |
171 | protected boolean hasFullScreen(){
172 | return hasFullscreen;
173 | }
174 |
175 | protected void setHasFullScreen(boolean hasFull){
176 | this.hasFullscreen = hasFull;
177 | }
178 |
179 | protected void setVideoUrl(String url){
180 | mUrl = url;
181 | }
182 |
183 | protected String getVideoUrl(){
184 | return mUrl;
185 | }
186 |
187 | protected void setThumbUrl(String url){
188 | thumbUrl = url;
189 | }
190 |
191 | protected String getThumbUrl(){
192 | return thumbUrl;
193 | }
194 | }
195 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/java/com/uis/lib/simpleplayer/player/PlayerCallback.java:
--------------------------------------------------------------------------------
1 | package com.uis.lib.simpleplayer.player;
2 |
3 | /**
4 | * @author uis on 2017/7/26.
5 | */
6 |
7 | public abstract class PlayerCallback {
8 | public void onPrepared(PlayerListener vp){}
9 | public void onBufferingUpdate(PlayerListener vp, int percent){}
10 | public void onCompletion(PlayerListener vp){}
11 | public void onSeekComplete(PlayerListener vp){}
12 | public void onInfo(PlayerListener vp, int what, int extra){}
13 | public void onError(PlayerListener vp, int what, int extra){}
14 | public void onProgress(int current,int total){}
15 | public void onVideoSizeChanged(PlayerListener vp, int width, int height){}
16 | }
17 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/java/com/uis/lib/simpleplayer/player/PlayerComplete.java:
--------------------------------------------------------------------------------
1 | package com.uis.lib.simpleplayer.player;
2 |
3 | /**
4 | * @author uis on 2017/11/25.
5 | */
6 |
7 | public interface PlayerComplete {
8 |
9 | int STATE_START = 0x00;
10 | int STATE_PAUSE = 0x01;
11 | int STATE_RELEASE = 0x02;
12 | int STATE_RESET = 0x03;
13 | int STATE_PREPARE = 0x04;
14 | int STATE_PREPARING = 0x05;
15 |
16 | void onChanged();
17 | void onComplete(int state);
18 | }
19 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/java/com/uis/lib/simpleplayer/player/PlayerControl.java:
--------------------------------------------------------------------------------
1 | package com.uis.lib.simpleplayer.player;
2 |
3 | import android.media.AudioManager;
4 | import android.media.MediaPlayer;
5 | import android.support.v4.util.ArrayMap;
6 | import android.view.Surface;
7 |
8 | import com.uis.lib.simpleplayer.Vlog;
9 |
10 |
11 | /**
12 | * MediaPlayer播放器
13 | * @author uis on 2017/11/25
14 | */
15 |
16 | final class PlayerControl implements PlayerListener {
17 |
18 | private final String TAG = "PlayerControl";
19 | private final static int sTimerMills = 300;
20 | private final PlayerListener mVideoPlayer;
21 | private final PlayerCounter mCounter;
22 |
23 | private MediaPlayer mPlayer;
24 | private ArrayMap mComplete = new ArrayMap<>();
25 | private PlayerCallback mCallback;
26 | private PlayerEntity mEntity;
27 | private Surface mSurface;
28 |
29 | private static PlayerListener newInstance(){
30 | return new PlayerControl();
31 | }
32 |
33 | private static class Inner{
34 | final static PlayerListener sPlayer = PlayerControl.newInstance();
35 | }
36 |
37 | public static PlayerListener createPlayer(){
38 | return Inner.sPlayer;
39 | }
40 |
41 | private PlayerControl(){
42 | mCounter = PlayerCounter.createCounter();
43 | mVideoPlayer = this;
44 | init();
45 | }
46 |
47 | private void startTimer(){
48 | mCounter.startTimer(sTimerMills,new InnerCount(this));
49 | }
50 |
51 | static class InnerCount implements Runnable{
52 | PlayerControl control;
53 | public InnerCount(PlayerControl c) {
54 | this.control = c;
55 | }
56 |
57 | @Override
58 | public void run() {
59 | if(control != null && control.mPlayer != null) {
60 | control.onProgress(control.getCurrentPosition());
61 | }
62 | }
63 | }
64 |
65 | private void stopTimer(){
66 | mCounter.stopTimer();
67 | }
68 |
69 | private void init(){
70 | Vlog.e(TAG,"-----init-----");
71 | mPlayer = new MediaPlayer();
72 | mPlayer.setScreenOnWhilePlaying(true);
73 | mPlayer.reset();
74 | mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
75 | @Override
76 | public void onPrepared(MediaPlayer mp) {
77 | Vlog.e(TAG,"------onPrepared------");
78 | if(mCallback != null){
79 | mCallback.onPrepared(mVideoPlayer);
80 | }
81 | boolean isPause = false;
82 | if(mEntity!=null) {
83 | mEntity.canPlay = true;
84 | isPause = mEntity.isPause;
85 | }
86 | if(!isPause) {
87 | start();
88 | }else{
89 | onComplete(PlayerComplete.STATE_PREPARE);
90 | }
91 | }
92 | });
93 |
94 | mPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
95 | @Override
96 | public void onBufferingUpdate(MediaPlayer mp, int percent) {
97 | if(mCallback != null){
98 | mCallback.onBufferingUpdate(mVideoPlayer,percent);
99 | }
100 | }
101 | });
102 |
103 | mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
104 | @Override
105 | public void onCompletion(MediaPlayer mp) {
106 | Vlog.i(TAG,"-----OnCompletionListener-----");
107 | onProgress(getDuration());
108 | if(mCallback != null) {
109 | mCallback.onCompletion(mVideoPlayer);
110 | }
111 | reset();
112 | }
113 | });
114 |
115 | mPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
116 | @Override
117 | public boolean onError(MediaPlayer mp, int what, int extra) {
118 | Vlog.i(TAG,"-----Error-----what="+what+",extra="+extra);
119 | if(mCallback != null) {
120 | mCallback.onError(mVideoPlayer, what, extra);
121 | }
122 | release();
123 | return true;
124 | }
125 | });
126 |
127 | mPlayer.setOnInfoListener(new MediaPlayer.OnInfoListener() {
128 | @Override
129 | public boolean onInfo(MediaPlayer mp, int what, int extra) {
130 | Vlog.i(TAG,"-----Info-----what="+what+",extra="+extra);
131 | if(mCallback != null) {
132 | mCallback.onInfo(mVideoPlayer, what, extra);
133 | }
134 | return true;
135 | }
136 | });
137 |
138 | mPlayer.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() {
139 | @Override
140 | public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
141 | if(mCallback != null) {
142 | mCallback.onVideoSizeChanged(mVideoPlayer, width, height);
143 | }
144 | }
145 | });
146 |
147 | mPlayer.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
148 | @Override
149 | public void onSeekComplete(MediaPlayer mp) {
150 | Vlog.i(TAG,getDuration()+"-----OnSeekCompleteListener-----"+getCurrentPosition());
151 | if(mCallback != null) {
152 | mCallback.onSeekComplete(mVideoPlayer);
153 | }
154 | onProgress(getCurrentPosition());
155 | if(isPlaying()) {
156 | start();
157 | }
158 | }
159 | });
160 | }
161 |
162 | /**
163 | * @param key (file-Path or http/rtsp url) to use
164 | */
165 | private void createEntityWhenNone(String key,String url){
166 | if(mEntity==null || !mEntity.key.equals(key)){
167 | mEntity = new PlayerEntity(key,url);
168 | }
169 | }
170 |
171 | private void prepare(){
172 | Vlog.e(TAG,"-------prepare---------");
173 | try {
174 | if(mEntity != null) {
175 | mPlayer.setDataSource(mEntity.url);
176 | mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
177 | mPlayer.prepareAsync();
178 | onComplete(PlayerComplete.STATE_PREPARING);
179 | }
180 | }catch (Exception ex){
181 | ex.printStackTrace();
182 | }
183 | }
184 |
185 | private void reset(){
186 | try{
187 | Vlog.e(TAG,"--------reset-----------");
188 | stopTimer();
189 | if(mPlayer!=null){
190 | mPlayer.reset();
191 | }
192 | }catch (Exception ex){
193 | ex.printStackTrace();
194 | }finally {
195 | onComplete(PlayerComplete.STATE_RESET);
196 | mPlayer = null;
197 | if(mEntity!=null){
198 | mEntity.canPrepare = true;
199 | mEntity.canPlay = false;
200 | mEntity.isPause = false;
201 | }
202 | }
203 | }
204 |
205 | @Override
206 | public void release(){
207 | try {
208 | Vlog.e(TAG,"--------release-----------");
209 | stopTimer();
210 | if(mPlayer!=null) {
211 | mPlayer.release();
212 | }
213 | }catch (Exception ex){
214 | ex.printStackTrace();
215 | }finally {
216 | onComplete(PlayerComplete.STATE_RELEASE);
217 | if(mEntity != null){
218 | mComplete.remove(mEntity.key);
219 | }
220 | mEntity = null;
221 | mPlayer = null;
222 | }
223 | }
224 |
225 | @Override
226 | public void setSurface(Surface surface){
227 | try{
228 | if(surface != null) {
229 | if (mPlayer != null) {
230 | mPlayer.setSurface(surface);
231 | }
232 | mSurface = surface;
233 | }
234 | }catch (Exception ex){
235 | ex.printStackTrace();
236 | }
237 | }
238 |
239 | @Override
240 | public void setVideoScalingMode(int mode) {
241 | if(mPlayer != null) {
242 | mPlayer.setVideoScalingMode(mode);
243 | }
244 | }
245 |
246 | @Override
247 | public void setVolume(float leftVolume, float rightVolume) {
248 | if(mPlayer != null) {
249 | mPlayer.setVolume(leftVolume, rightVolume);
250 | }
251 | }
252 |
253 | @Override
254 | public void setLooping(boolean isLoop) {
255 | if(mPlayer != null) {
256 | mPlayer.setLooping(isLoop);
257 | }
258 | }
259 |
260 | @Override
261 | public void prepare(String key,String url) {
262 | Vlog.e(TAG,"----prepare---mEntity is null = "+(mEntity==null));
263 | if(mEntity!=null && !mEntity.key.equals(key)){
264 | release();
265 | }
266 | if(mPlayer==null){
267 | init();
268 | }
269 | createEntityWhenNone(key,url);
270 | if(mEntity.canPrepare){
271 | prepare();
272 | setSurface(mSurface);
273 | mEntity.canPrepare = false;
274 | }else{
275 | start();
276 | }
277 | }
278 |
279 | @Override
280 | public boolean isPlaying(){
281 | return mEntity!=null && isPlaying(mEntity.url);
282 | }
283 |
284 | @Override
285 | public boolean isPlaying(String key) {
286 | boolean isPlaying = false;
287 | try {
288 | if (mPlayer!=null && mEntity!=null && mEntity.url.equals(key) && mPlayer.isPlaying()) {
289 | isPlaying = true;
290 | }
291 | }catch (Exception ex){
292 | //ex.printStackTrace();
293 | }
294 | Vlog.e(TAG,"------isPlaying----"+isPlaying+",key="+key);
295 | return isPlaying;
296 | }
297 |
298 | @Override
299 | public boolean isRelease() {
300 | return (mPlayer!=null && mEntity == null) || mPlayer==null || mCallback==null;
301 | }
302 |
303 | @Override
304 | public void start(){
305 | try{
306 | Vlog.e(TAG,"--------start-----------"+isPlaying());
307 | if(mPlayer!=null && !isPlaying() && mEntity!=null && mEntity.canPlay) {
308 | mPlayer.start();
309 | startTimer();
310 | onComplete(PlayerComplete.STATE_START);
311 | if(mEntity != null){
312 | mEntity.isPause = false;
313 | }
314 | }
315 | }catch (Exception ex){
316 | ex.printStackTrace();
317 | }
318 | }
319 |
320 | @Override
321 | public void seekTo(int millsec) {
322 | try {
323 | Vlog.e(TAG,"-----------seek----------"+millsec);
324 | if(mEntity!=null && mEntity.canPlay) {
325 | mPlayer.seekTo(millsec);
326 | }
327 | }catch (Exception ex) {
328 | ex.printStackTrace();
329 | }
330 | }
331 |
332 | @Override
333 | public void pause(){
334 | try {
335 | Vlog.e(TAG,"--------pause-----------");
336 | stopTimer();
337 | if(mPlayer!=null && isPlaying()) {
338 | mPlayer.pause();
339 | if(mEntity != null){
340 | mEntity.isPause = true;
341 | }
342 | onComplete(PlayerComplete.STATE_PAUSE);
343 | }
344 | }catch (Exception ex){
345 | ex.printStackTrace();
346 | }
347 | }
348 |
349 | @Override
350 | public void releasePlayer() {
351 | release();
352 | Vlog.e(TAG,"--mComplete--size="+mComplete.size()+"\n"+mComplete);
353 | mCallback = null;
354 | }
355 |
356 | @Override
357 | public int getDuration() {
358 | int duration = 0;
359 | try {
360 | if(mPlayer!=null) {
361 | duration = mPlayer.getDuration();
362 | }
363 | }catch (Exception ex){
364 | ex.printStackTrace();
365 | }
366 | return duration;
367 | }
368 |
369 | @Override
370 | public int getCurrentPosition(){
371 | int duration = 0;
372 | try {
373 | if(mPlayer!=null) {
374 | duration = mPlayer.getCurrentPosition();
375 | }
376 | }catch (Exception ex){
377 | ex.printStackTrace();
378 | }
379 | return duration;
380 | }
381 |
382 | @Override
383 | public int getVideoWidth() {
384 | return mPlayer==null ? 0:mPlayer.getVideoWidth();
385 | }
386 |
387 | @Override
388 | public int getVideoHeight() {
389 | return mPlayer==null ? 0:mPlayer.getVideoHeight();
390 | }
391 |
392 | @Override
393 | public void onProgress(int current) {
394 | if(mEntity==null || mEntity.current != current) {
395 | if(mEntity!=null){
396 | mEntity.current = current;
397 | }
398 | int mTotal = getDuration();
399 | if(mCallback != null && current <= mTotal) {
400 | mCallback.onProgress(current, mTotal);
401 | }
402 | }
403 | }
404 |
405 | @Override
406 | public void registerPlayer(String key, PlayerCallback callback,PlayerComplete complete){
407 | if(mCallback != callback){
408 | mCallback = callback;
409 | }
410 | if(complete!=null && !mComplete.containsKey(key)){
411 | mComplete.put(key,complete);
412 | }
413 | }
414 |
415 | @Override
416 | public void onChanged(String key){
417 | if(mComplete.containsKey(key)){
418 | mComplete.get(key).onChanged();
419 | }
420 | }
421 |
422 | private void onComplete(int state){
423 | Vlog.e(TAG,"----------onComplete------"+state);
424 | if(mEntity != null) {
425 | String key = mEntity.key;
426 | if (mComplete.containsKey(key)) {
427 | mComplete.get(key).onComplete(state);
428 | if(PlayerComplete.STATE_RELEASE == state) {
429 | mComplete.remove(key);
430 | }
431 | }
432 | }
433 | }
434 | }
435 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/java/com/uis/lib/simpleplayer/player/PlayerCounter.java:
--------------------------------------------------------------------------------
1 | package com.uis.lib.simpleplayer.player;
2 |
3 | import android.os.Handler;
4 | import android.os.Looper;
5 |
6 | import java.util.Timer;
7 | import java.util.TimerTask;
8 |
9 | /**
10 | * @author uis on 2017/11/25.
11 | */
12 |
13 | public class PlayerCounter {
14 |
15 | public static Handler mHandler = new Handler(Looper.getMainLooper());
16 | private Timer mTimer;
17 |
18 | public static PlayerCounter createCounter(){
19 | return new PlayerCounter();
20 | }
21 |
22 | private PlayerCounter() {
23 | }
24 |
25 | public void startTimer(int mills,Runnable run){
26 | this.startTimer(true,true,mills,run);
27 | }
28 |
29 | public void startTimer(boolean isMainLoop,boolean isLooper,int mills,Runnable run){
30 | if(mTimer == null) {
31 | mTimer = new Timer();
32 | if(isLooper) {
33 | mTimer.schedule(getTimerTask(isMainLoop, run), 0, mills);
34 | }else{
35 | mTimer.schedule(getTimerTask(isMainLoop, run),mills);
36 | }
37 | }
38 | }
39 |
40 | public void stopTimer(){
41 | if(mTimer != null) {
42 | mTimer.cancel();
43 | mTimer = null;
44 | }
45 | }
46 |
47 | /**
48 | * 每次需要重新创建,因为stop时候有cancel
49 | * @return
50 | */
51 | private TimerTask getTimerTask(final boolean isMainLoop, final Runnable run){
52 | return new TimerTask() {
53 | @Override
54 | public void run() {
55 | if(mTimer == null){
56 | return;
57 | }
58 | if(isMainLoop){
59 | mHandler.post(run);
60 | }else{
61 | run.run();
62 | }
63 | }
64 | };
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/java/com/uis/lib/simpleplayer/player/PlayerEntity.java:
--------------------------------------------------------------------------------
1 | package com.uis.lib.simpleplayer.player;
2 |
3 | /**
4 | * @author uis on 2017/11/21.
5 | */
6 |
7 | final class PlayerEntity {
8 | public String url;
9 | public int current = 0;
10 | public String key;
11 | public boolean canPrepare = true;
12 | public boolean canPlay = false;
13 | public boolean isPause = false;
14 |
15 | public PlayerEntity(String key,String url) {
16 | this.url = url;
17 | this.key = key;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/java/com/uis/lib/simpleplayer/player/PlayerListener.java:
--------------------------------------------------------------------------------
1 | package com.uis.lib.simpleplayer.player;
2 |
3 | import android.view.Surface;
4 |
5 | /**
6 | * 播放控制
7 | * @author uis on 2017/7/26.
8 | */
9 |
10 | public interface PlayerListener {
11 | void setVolume(float leftVolume, float rightVolume);
12 | void setLooping(boolean isLoop);
13 | void setVideoScalingMode(int mode);
14 | void setSurface(Surface surface);
15 |
16 | void prepare(String key,String url);
17 | void start();
18 | void seekTo(int millsec);
19 | void pause();
20 | void release();
21 | void releasePlayer();
22 |
23 | int getDuration();
24 | int getCurrentPosition();
25 | int getVideoWidth();
26 | int getVideoHeight();
27 | void onProgress(int current);
28 | void registerPlayer(String key, PlayerCallback callback, PlayerComplete complete);
29 | void onChanged(String key);
30 |
31 | boolean isPlaying(String url);
32 | boolean isPlaying();
33 | boolean isRelease();
34 | }
35 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/java/com/uis/lib/simpleplayer/player/PlayerUtils.java:
--------------------------------------------------------------------------------
1 | package com.uis.lib.simpleplayer.player;
2 |
3 | import android.app.ActionBar;
4 | import android.app.Activity;
5 | import android.content.Context;
6 | import android.content.res.Resources;
7 | import android.net.ConnectivityManager;
8 | import android.net.NetworkInfo;
9 | import android.support.v7.app.AppCompatActivity;
10 | import android.text.TextUtils;
11 | import android.widget.FrameLayout;
12 | import android.widget.Toast;
13 |
14 | import com.uis.lib.simpleplayer.PlayerLayout;
15 |
16 | /**
17 | * @author uis on 2017/11/21.
18 | */
19 |
20 | public class PlayerUtils {
21 |
22 | public static void pause(){
23 | PlayerControl.createPlayer().pause();
24 | }
25 |
26 | public static boolean isPlaying(){
27 | return PlayerControl.createPlayer().isPlaying();
28 | }
29 |
30 | public static boolean isPlaying(String videoPath){
31 | return PlayerControl.createPlayer().isPlaying(videoPath);
32 | }
33 |
34 | public static boolean isRelease(){
35 | return PlayerControl.createPlayer().isRelease();
36 | }
37 |
38 | public static void start(){
39 | PlayerControl.createPlayer().start();
40 | }
41 |
42 | public static void release(){
43 | PlayerControl.createPlayer().releasePlayer();
44 | }
45 |
46 | public static void showActionBar(Context mc){
47 | if(mc!=null) {
48 | ActionBar bar = ((Activity) mc).getActionBar();
49 | if(bar!=null) {
50 | bar.show();
51 | }else if(mc instanceof AppCompatActivity){
52 | android.support.v7.app.ActionBar abar = ((AppCompatActivity) mc).getSupportActionBar();
53 | if(abar!=null) {
54 | abar.show();
55 | }
56 | }
57 | }
58 | }
59 |
60 | public static void hideActionBar(Context mc){
61 | if(mc!=null) {
62 | ActionBar bar = ((Activity) mc).getActionBar();
63 | if(bar!=null) {
64 | bar.hide();
65 | }else if(mc instanceof AppCompatActivity){
66 | android.support.v7.app.ActionBar abar = ((AppCompatActivity) mc).getSupportActionBar();
67 | if(abar!=null) {
68 | abar.hide();
69 | }
70 | }
71 | }
72 | }
73 |
74 | public static void toast(Context context,String msg){
75 | if(context!=null && !TextUtils.isEmpty(msg)) {
76 | Toast.makeText(context, msg,Toast.LENGTH_SHORT).show();
77 | }
78 | }
79 |
80 | public static boolean isConnected(Context context) {
81 | ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
82 | NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
83 | return networkInfo != null && networkInfo.isConnected();
84 | }
85 |
86 | public static boolean isWifiConnected(Context context) {
87 | ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
88 | NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
89 | return networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI;
90 | }
91 |
92 | public static boolean isMobileConnected(Context context) {
93 | ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
94 | NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
95 | return networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_MOBILE;
96 | }
97 |
98 | public static String getTime(int current){
99 | StringBuilder builder = new StringBuilder();
100 | current /= 1000;
101 | if(current>60){//60s
102 | if(current<600){//600s
103 | builder.append("0");
104 | }
105 | builder.append(current/60);
106 | }else{
107 | builder.append("00");
108 | }
109 | builder.append(":");
110 | int seconds = current%60;
111 | if(seconds<10){//10s
112 | builder.append("0");
113 | }
114 | builder.append(seconds);
115 | return builder.toString();
116 | }
117 |
118 | public static String getUniqueCode(int unique,String url){
119 | return String.valueOf(new StringBuilder(url).append(unique).toString().hashCode());
120 | }
121 |
122 | public static double getRate(int maxRate,int current,int total){
123 | return maxRate*(1.0d*current/total);
124 | }
125 |
126 | public static PlayerView initPlayer(Context mc){
127 | if(InitPlayer.sPlayer == null) {
128 | InitPlayer.sPlayer = new PlayerView(mc);
129 | InitPlayer.sPlayer.setLayoutParams(
130 | new FrameLayout.LayoutParams(
131 | FrameLayout.LayoutParams.MATCH_PARENT,
132 | FrameLayout.LayoutParams.MATCH_PARENT
133 | ));
134 | }
135 | return InitPlayer.sPlayer;
136 | }
137 |
138 | public static int getPlayerWidth(){
139 | return InitPlayer.sWidth;
140 | }
141 |
142 | public static int getPlayerHeight(){
143 | return InitPlayer.sHeight;
144 | }
145 |
146 | static class InitPlayer{
147 | static PlayerView sPlayer;
148 | static int sWidth = Resources.getSystem().getDisplayMetrics().widthPixels;
149 | static int sHeight = Resources.getSystem().getDisplayMetrics().heightPixels;
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/java/com/uis/lib/simpleplayer/player/PlayerView.java:
--------------------------------------------------------------------------------
1 | package com.uis.lib.simpleplayer.player;
2 |
3 | import android.annotation.TargetApi;
4 | import android.app.Activity;
5 | import android.content.Context;
6 | import android.content.res.Configuration;
7 | import android.graphics.SurfaceTexture;
8 | import android.util.AttributeSet;
9 | import android.view.Gravity;
10 | import android.view.Surface;
11 | import android.view.TextureView;
12 | import android.view.ViewGroup;
13 | import android.widget.FrameLayout;
14 |
15 | import com.uis.lib.simpleplayer.Vlog;
16 |
17 | /**
18 | * 播放显示器
19 | * @author uis on 2017/11/21.
20 | */
21 |
22 | final class PlayerView extends TextureView implements TextureView.SurfaceTextureListener{
23 |
24 | private final static String TAG = "PlayerView";
25 | protected PlayerListener mPlayer;
26 | private SurfaceTexture savedSurface;
27 | private boolean isFullScreen = false;
28 | private String url;
29 | private String key;
30 | private static int sWidth = PlayerUtils.getPlayerWidth();
31 | private static int sHeight = PlayerUtils.getPlayerHeight();
32 | private static long sResizeTime;
33 |
34 | public PlayerView(Context context) {
35 | this(context,null);
36 | }
37 |
38 | public PlayerView(Context context, AttributeSet attrs) {
39 | this(context, attrs,0);
40 | }
41 |
42 | public PlayerView(Context context, AttributeSet attrs, int defStyleAttr) {
43 | super(context, attrs, defStyleAttr);
44 | init();
45 | }
46 |
47 | @TargetApi(21)
48 | public PlayerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
49 | super(context, attrs, defStyleAttr, defStyleRes);
50 | init();
51 | }
52 |
53 | @Override
54 | protected void onConfigurationChanged(Configuration newConfig) {
55 | if(isFullScreen) {
56 | resize(newConfig.orientation);
57 | }
58 | }
59 |
60 | private void init(){
61 | if(!isInEditMode()) {
62 | mPlayer = PlayerControl.createPlayer();
63 | setSurfaceTextureListener(this);
64 | }
65 | }
66 |
67 | public void setFullScreen(boolean isFull){
68 | isFullScreen = isFull;
69 | }
70 |
71 | public void setDataSource(int unique,String url, PlayerCallback callback, PlayerComplete complete){
72 | this.url = url;
73 | this.key = PlayerUtils.getUniqueCode(unique,url);
74 | mPlayer.registerPlayer(key,callback,complete);
75 | }
76 |
77 | public void prepare(){
78 | mPlayer.prepare(key,url);
79 | }
80 |
81 | public void seekTo(int time){
82 | if(mPlayer.isRelease()) {
83 | prepare();
84 | }else{
85 | mPlayer.seekTo(time);
86 | }
87 | }
88 |
89 | public boolean isPlaying(){
90 | return mPlayer.isPlaying(url);
91 | }
92 |
93 | public boolean isRelease(){
94 | return mPlayer.isRelease();
95 | }
96 |
97 | public void pause(){
98 | mPlayer.pause();
99 | }
100 |
101 | void resize(){
102 | resize(1);
103 | }
104 |
105 | void resize(int config){
106 | if(System.currentTimeMillis() - sResizeTime < 100){
107 | return;
108 | }
109 | int w = mPlayer.getVideoWidth();
110 | int h = mPlayer.getVideoHeight();
111 | if(w<=0 || h<=0){
112 | return;
113 | }
114 | int screenW,screenH;
115 | ViewGroup root = (ViewGroup)getParent();
116 | if(root==null){
117 | return;
118 | }
119 | if(isFullScreen){
120 | if(Configuration.ORIENTATION_LANDSCAPE == config){
121 | screenW = sHeight;
122 | screenH = sWidth;
123 | }else{
124 | screenW = sWidth;
125 | screenH = sHeight;
126 | }
127 | }else{
128 | screenW = root.getWidth();
129 | screenH = root.getHeight();
130 | }
131 | if(getRate(w,h) >= getRate(screenW,screenH)){//fixed width
132 | h = screenW * h / w;
133 | w = screenW;
134 | }else{//fixed height
135 | w = screenH * w / h;
136 | h = screenH;
137 | }
138 | Vlog.e(TAG,"screenW="+screenW+",screenH="+screenH+",w="+w+",h="+h);
139 | ViewGroup.LayoutParams mParams = getLayoutParams();
140 | if(mParams.width!=w || mParams.height!=h) {
141 | mParams.width = w;
142 | mParams.height = h;
143 | if (mParams instanceof FrameLayout.LayoutParams) {
144 | ((FrameLayout.LayoutParams) mParams).gravity = Gravity.CENTER;
145 | }
146 | setLayoutParams(mParams);
147 | sResizeTime = System.currentTimeMillis();
148 | }
149 | }
150 |
151 | void onChanged(){
152 | if(isFullScreen && mPlayer!=null) {
153 | mPlayer.onChanged(key);
154 | }
155 | }
156 |
157 | private float getRate(int a,int b){
158 | return 1.0f*a/b;
159 | }
160 |
161 | @Override
162 | public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
163 | if(savedSurface == null) {
164 | savedSurface = surface;
165 | mPlayer.setSurface(new Surface(savedSurface));
166 | }else{
167 | setSurfaceTexture(savedSurface);
168 | }
169 | }
170 |
171 | @Override
172 | public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
173 |
174 | }
175 |
176 | @Override
177 | public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
178 | return false;
179 | }
180 |
181 | @Override
182 | public void onSurfaceTextureUpdated(SurfaceTexture surface) {
183 |
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/drawable/bg_black_trans.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/drawable/btn_video_back.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/drawable/btn_video_close.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/drawable/btn_video_restart.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/drawable/color_bt_back.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/drawable/color_pb_red.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/drawable/color_pb_white.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/drawable/color_pb_white_trans.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/drawable/pb_video_gray.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
11 |
16 |
24 |
25 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/drawable/pb_video_progress.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
5 |
6 | -
7 |
8 |
9 | -
10 |
11 |
12 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/drawable/sbar_thumb_normal.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/drawable/sbar_thumb_pressed.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/drawable/sbar_video_thumb.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/layout/video_player_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
12 |
20 |
33 |
40 |
49 |
57 |
66 |
74 |
75 |
83 |
91 |
102 |
110 |
117 |
127 |
134 |
142 |
143 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/mipmap-xhdpi/video_back_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luiing/SimplePlayer/48af00a01bdf27e962c8214912c4b23629c5235a/lib-simpleplayer/src/main/res/mipmap-xhdpi/video_back_normal.png
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/mipmap-xhdpi/video_back_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luiing/SimplePlayer/48af00a01bdf27e962c8214912c4b23629c5235a/lib-simpleplayer/src/main/res/mipmap-xhdpi/video_back_pressed.png
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/mipmap-xhdpi/video_close_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luiing/SimplePlayer/48af00a01bdf27e962c8214912c4b23629c5235a/lib-simpleplayer/src/main/res/mipmap-xhdpi/video_close_normal.png
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/mipmap-xhdpi/video_close_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luiing/SimplePlayer/48af00a01bdf27e962c8214912c4b23629c5235a/lib-simpleplayer/src/main/res/mipmap-xhdpi/video_close_pressed.png
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/mipmap-xhdpi/video_restart_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luiing/SimplePlayer/48af00a01bdf27e962c8214912c4b23629c5235a/lib-simpleplayer/src/main/res/mipmap-xhdpi/video_restart_normal.png
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/mipmap-xhdpi/video_restart_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luiing/SimplePlayer/48af00a01bdf27e962c8214912c4b23629c5235a/lib-simpleplayer/src/main/res/mipmap-xhdpi/video_restart_pressed.png
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/mipmap-xxhdpi/fullscreen_exit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luiing/SimplePlayer/48af00a01bdf27e962c8214912c4b23629c5235a/lib-simpleplayer/src/main/res/mipmap-xxhdpi/fullscreen_exit.png
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/mipmap-xxhdpi/fullscreen_start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luiing/SimplePlayer/48af00a01bdf27e962c8214912c4b23629c5235a/lib-simpleplayer/src/main/res/mipmap-xxhdpi/fullscreen_start.png
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/mipmap-xxhdpi/video_pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luiing/SimplePlayer/48af00a01bdf27e962c8214912c4b23629c5235a/lib-simpleplayer/src/main/res/mipmap-xxhdpi/video_pause.png
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/mipmap-xxhdpi/video_play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luiing/SimplePlayer/48af00a01bdf27e962c8214912c4b23629c5235a/lib-simpleplayer/src/main/res/mipmap-xxhdpi/video_play.png
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/mipmap-xxhdpi/video_play_s.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luiing/SimplePlayer/48af00a01bdf27e962c8214912c4b23629c5235a/lib-simpleplayer/src/main/res/mipmap-xxhdpi/video_play_s.png
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/values/video_attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/lib-simpleplayer/src/main/res/values/video_ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':lib-simpleplayer'
2 | include ':demo'
3 |
4 |
5 |
--------------------------------------------------------------------------------
/snapshot/2017-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luiing/SimplePlayer/48af00a01bdf27e962c8214912c4b23629c5235a/snapshot/2017-1.png
--------------------------------------------------------------------------------
/snapshot/2017-11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luiing/SimplePlayer/48af00a01bdf27e962c8214912c4b23629c5235a/snapshot/2017-11.png
--------------------------------------------------------------------------------
/snapshot/2017-12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luiing/SimplePlayer/48af00a01bdf27e962c8214912c4b23629c5235a/snapshot/2017-12.png
--------------------------------------------------------------------------------
/snapshot/2017-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luiing/SimplePlayer/48af00a01bdf27e962c8214912c4b23629c5235a/snapshot/2017-2.png
--------------------------------------------------------------------------------
/snapshot/2017-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luiing/SimplePlayer/48af00a01bdf27e962c8214912c4b23629c5235a/snapshot/2017-3.png
--------------------------------------------------------------------------------
/snapshot/device-2017-001.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luiing/SimplePlayer/48af00a01bdf27e962c8214912c4b23629c5235a/snapshot/device-2017-001.png
--------------------------------------------------------------------------------
/snapshot/device-2017-002.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luiing/SimplePlayer/48af00a01bdf27e962c8214912c4b23629c5235a/snapshot/device-2017-002.png
--------------------------------------------------------------------------------
/snapshot/device-2017-003.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luiing/SimplePlayer/48af00a01bdf27e962c8214912c4b23629c5235a/snapshot/device-2017-003.png
--------------------------------------------------------------------------------