├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── values
│ │ │ │ ├── colors.xml
│ │ │ │ ├── styles.xml
│ │ │ │ └── strings.xml
│ │ │ └── layout
│ │ │ │ ├── adapter_player.xml
│ │ │ │ ├── activity_simple.xml
│ │ │ │ ├── activity_list.xml
│ │ │ │ └── activity_main.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── d
│ │ │ │ └── commenplayer
│ │ │ │ ├── App.java
│ │ │ │ ├── model
│ │ │ │ └── MediaModel.java
│ │ │ │ ├── adapter
│ │ │ │ ├── PlayerAdapter.java
│ │ │ │ └── PlayerItem.java
│ │ │ │ ├── MainActivity.java
│ │ │ │ └── activity
│ │ │ │ ├── SimpleActivity.java
│ │ │ │ └── ListActivity.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── d
│ │ │ └── commenplayer
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── d
│ │ └── commenplayer
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── lib
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── drawable-xhdpi
│ │ │ │ ├── lib_player_ic_back.png
│ │ │ │ ├── lib_player_ic_play.png
│ │ │ │ ├── lib_player_ic_pause.png
│ │ │ │ ├── lib_player_ic_volume.png
│ │ │ │ ├── lib_player_ic_aplayer.png
│ │ │ │ ├── lib_player_ic_backward.png
│ │ │ │ ├── lib_player_ic_forward.png
│ │ │ │ ├── lib_player_ic_loading.png
│ │ │ │ ├── lib_player_ic_brightness.png
│ │ │ │ ├── lib_player_ic_fullscreen_in.png
│ │ │ │ └── lib_player_ic_fullscreen_out.png
│ │ │ ├── drawable
│ │ │ │ ├── lib_player_corner_bg_control.xml
│ │ │ │ ├── lib_player_corner_bg_6.xml
│ │ │ │ ├── lib_player_gradient_bg_top.xml
│ │ │ │ ├── lib_player_gradient_bg_bottom.xml
│ │ │ │ ├── lib_player_loading.xml
│ │ │ │ ├── lib_player_seekbar_play_thumb.xml
│ │ │ │ ├── lib_player_seekbar_adjust.xml
│ │ │ │ └── lib_player_seekbar_play.xml
│ │ │ ├── values-zh-rCN
│ │ │ │ └── strings.xml
│ │ │ ├── values
│ │ │ │ └── strings.xml
│ │ │ └── layout
│ │ │ │ ├── lib_player_layout_aplayer.xml
│ │ │ │ ├── lib_player_layout_player.xml
│ │ │ │ ├── lib_player_layout_touch.xml
│ │ │ │ └── lib_player_layout_control.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── d
│ │ │ │ └── lib
│ │ │ │ └── commenplayer
│ │ │ │ ├── listener
│ │ │ │ ├── OnNetworkListener.java
│ │ │ │ ├── OnAnimatorUpdateListener.java
│ │ │ │ ├── OnShowThumbnailListener.java
│ │ │ │ ├── IPlayerListener.java
│ │ │ │ ├── IMediaPlayerControl.java
│ │ │ │ └── IRenderView.java
│ │ │ │ ├── util
│ │ │ │ ├── FileMediaDataSource.java
│ │ │ │ ├── Settings.java
│ │ │ │ ├── MediaPlayerCompat.java
│ │ │ │ ├── ULog.java
│ │ │ │ ├── Factory.java
│ │ │ │ ├── InfoHudViewHolder.java
│ │ │ │ └── InfoUtil.java
│ │ │ │ ├── services
│ │ │ │ └── MediaPlayerService.java
│ │ │ │ ├── media
│ │ │ │ ├── MeasureHelper.java
│ │ │ │ ├── SurfaceRenderView.java
│ │ │ │ ├── MediaManager.java
│ │ │ │ ├── TextureRenderView.java
│ │ │ │ └── IjkVideoView.java
│ │ │ │ ├── widget
│ │ │ │ └── TouchLayout.java
│ │ │ │ └── CommenPlayer.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── d
│ │ │ └── lib
│ │ │ └── commenplayer
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── d
│ │ └── lib
│ │ └── commenplayer
│ │ └── ExampleInstrumentedTest.java
├── consumer-proguard-rules.pro
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── logo
├── logomark-black.png
├── logomark-color.png
├── logomark-white.png
├── vertical-black.png
├── vertical-color.png
├── vertical-white.png
├── horizontal-black.png
├── horizontal-color.png
└── horizontal-white.png
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── CHANGELOG.md
├── doc
├── bashrc
├── compile-ijkplayer-zh.md
└── compile-ijkplayer.md
├── .gitignore
├── gradle.properties
├── gradlew.bat
├── README-zh.md
├── gradlew
└── README.md
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/lib/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':lib'
2 |
--------------------------------------------------------------------------------
/logo/logomark-black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/logo/logomark-black.png
--------------------------------------------------------------------------------
/logo/logomark-color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/logo/logomark-color.png
--------------------------------------------------------------------------------
/logo/logomark-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/logo/logomark-white.png
--------------------------------------------------------------------------------
/logo/vertical-black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/logo/vertical-black.png
--------------------------------------------------------------------------------
/logo/vertical-color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/logo/vertical-color.png
--------------------------------------------------------------------------------
/logo/vertical-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/logo/vertical-white.png
--------------------------------------------------------------------------------
/logo/horizontal-black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/logo/horizontal-black.png
--------------------------------------------------------------------------------
/logo/horizontal-color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/logo/horizontal-color.png
--------------------------------------------------------------------------------
/logo/horizontal-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/logo/horizontal-white.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/lib/src/main/res/drawable-xhdpi/lib_player_ic_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/lib/src/main/res/drawable-xhdpi/lib_player_ic_back.png
--------------------------------------------------------------------------------
/lib/src/main/res/drawable-xhdpi/lib_player_ic_play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/lib/src/main/res/drawable-xhdpi/lib_player_ic_play.png
--------------------------------------------------------------------------------
/lib/src/main/res/drawable-xhdpi/lib_player_ic_pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/lib/src/main/res/drawable-xhdpi/lib_player_ic_pause.png
--------------------------------------------------------------------------------
/lib/src/main/res/drawable-xhdpi/lib_player_ic_volume.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/lib/src/main/res/drawable-xhdpi/lib_player_ic_volume.png
--------------------------------------------------------------------------------
/lib/src/main/res/drawable-xhdpi/lib_player_ic_aplayer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/lib/src/main/res/drawable-xhdpi/lib_player_ic_aplayer.png
--------------------------------------------------------------------------------
/lib/src/main/res/drawable-xhdpi/lib_player_ic_backward.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/lib/src/main/res/drawable-xhdpi/lib_player_ic_backward.png
--------------------------------------------------------------------------------
/lib/src/main/res/drawable-xhdpi/lib_player_ic_forward.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/lib/src/main/res/drawable-xhdpi/lib_player_ic_forward.png
--------------------------------------------------------------------------------
/lib/src/main/res/drawable-xhdpi/lib_player_ic_loading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/lib/src/main/res/drawable-xhdpi/lib_player_ic_loading.png
--------------------------------------------------------------------------------
/lib/src/main/res/drawable-xhdpi/lib_player_ic_brightness.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/lib/src/main/res/drawable-xhdpi/lib_player_ic_brightness.png
--------------------------------------------------------------------------------
/lib/src/main/res/drawable-xhdpi/lib_player_ic_fullscreen_in.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/lib/src/main/res/drawable-xhdpi/lib_player_ic_fullscreen_in.png
--------------------------------------------------------------------------------
/lib/src/main/res/drawable-xhdpi/lib_player_ic_fullscreen_out.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dsiner/CommenPlayer/HEAD/lib/src/main/res/drawable-xhdpi/lib_player_ic_fullscreen_out.png
--------------------------------------------------------------------------------
/lib/src/main/java/com/d/lib/commenplayer/listener/OnNetworkListener.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer.listener;
2 |
3 | public interface OnNetworkListener {
4 | void onIgnoreMobileData();
5 | }
6 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/d/lib/commenplayer/listener/OnAnimatorUpdateListener.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer.listener;
2 |
3 | public interface OnAnimatorUpdateListener {
4 | void onAnimationUpdate(float factor);
5 | }
6 |
--------------------------------------------------------------------------------
/lib/consumer-proguard-rules.pro:
--------------------------------------------------------------------------------
1 | -keep class com.d.lib.commenplayer.** {*;}
2 |
3 | -keep class tv.danmaku.ijk.media.** {*;}
4 |
5 | -dontwarn com.nineoldandroids.**
6 | -keep class com.nineoldandroids.** {*;}
7 | -keep interface com.nineoldandroids.** {*;}
8 |
--------------------------------------------------------------------------------
/lib/src/main/res/drawable/lib_player_corner_bg_control.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/lib/src/main/res/drawable/lib_player_corner_bg_6.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon May 29 13:25:39 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.4-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #000000
7 |
8 |
--------------------------------------------------------------------------------
/lib/src/main/res/drawable/lib_player_gradient_bg_top.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
--------------------------------------------------------------------------------
/lib/src/main/res/drawable/lib_player_gradient_bg_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
--------------------------------------------------------------------------------
/lib/src/main/res/drawable/lib_player_loading.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | Changelog
2 | --------------------------------
3 |
4 | Version: Last
5 | --------------------------------
6 | - Internationalization
7 | - Optimization
8 | - Gradle: upgrade to 4.4
9 |
10 | Version: 1.0.1
11 | --------------------------------
12 | - resourcePrefix
13 |
14 | Version: 1.0.0
15 | --------------------------------
16 | - Initial Build
--------------------------------------------------------------------------------
/lib/src/main/java/com/d/lib/commenplayer/listener/OnShowThumbnailListener.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer.listener;
2 |
3 | import android.widget.ImageView;
4 |
5 | public interface OnShowThumbnailListener {
6 |
7 | /**
8 | * Return the cover view, let the user set it autonomously
9 | */
10 | void onShowThumbnail(ImageView ivThumbnail);
11 | }
12 |
--------------------------------------------------------------------------------
/lib/src/main/res/drawable/lib_player_seekbar_play_thumb.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/doc/bashrc:
--------------------------------------------------------------------------------
1 | export JAVA_HOME=/home/dsiner/Dev/App/jdk1.8.0_131
2 | export JRE_HOME=${JAVA_HOME}/jre
3 | export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
4 | export PATH=${JAVA_HOME}/bin:$PATH
5 |
6 | export ANDROID_SDK=/home/dsiner/Dev/App/android-sdk-linux
7 | export PATH=${PATH}:$ANDROID_SDK/tools:$ANDROID_SDK/platform-tools
8 |
9 | export ANDROID_NDK=/home/dsiner/Dev/App/android-ndk-r13
10 | export PATH=$PATH:ANDROID_NDK
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/d/commenplayer/App.java:
--------------------------------------------------------------------------------
1 | package com.d.commenplayer;
2 |
3 | import android.app.Application;
4 |
5 | import com.d.lib.common.component.network.NetworkCompat;
6 |
7 | /**
8 | * App
9 | * Created by D on 2018/9/22.
10 | */
11 | public class App extends Application {
12 |
13 | @Override
14 | public void onCreate() {
15 | super.onCreate();
16 | NetworkCompat.init(getApplicationContext());
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/test/java/com/d/commenplayer/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.d.commenplayer;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/lib/src/main/res/values-zh-rCN/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 当前为移动网络,是否继续播放?
4 | 继续播放
5 | 播放结束,是否重新播放?
6 | 重新播放
7 | 播放失败,是否重试?
8 | 重试
9 |
10 |
--------------------------------------------------------------------------------
/lib/src/test/java/com/d/lib/commenplayer/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/lib/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Currently mobile data, do you want to continue playing?
4 | Continue playing
5 | End of playback, replay?
6 | Replay
7 | Play failed, retry?
8 | Retry
9 |
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.DS_Store
2 |
3 | # Built application files
4 | *.apk
5 | *.ap_
6 |
7 | # Files for the ART/Dalvik VM
8 | *.dex
9 |
10 | # Java class files
11 | *.class
12 |
13 | # Generated files
14 | bin/
15 | gen/
16 | out/
17 |
18 | # Gradle files
19 | .gradle/
20 | build/
21 |
22 | # Local configuration file (sdk path, etc)
23 | local.properties
24 |
25 | # Proguard folder generated by Eclipse
26 | proguard/
27 |
28 | # Log Files
29 | *.log
30 |
31 | # Android Studio Navigation editor temp files
32 | .navigation/
33 |
34 | # Android Studio captures folder
35 | captures/
36 |
37 | # Intellij
38 | *.iml
39 | .idea/
40 |
41 | # Keystore files
42 | *.jks
--------------------------------------------------------------------------------
/lib/src/main/res/drawable/lib_player_seekbar_adjust.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 | -
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/adapter_player.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
18 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 |
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | org.gradle.jvmargs=-Xmx1536m -Dfile.encoding=UTF-8
15 | android.injected.testOnly=false
--------------------------------------------------------------------------------
/lib/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/d/commenplayer/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.d.commenplayer;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.d.commenplayer", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/src/androidTest/java/com/d/lib/commenplayer/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.d.lib.commenplayer.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | CommenPlayer
4 |
5 | http://vpls.cdn.videojj.com/scene/video02_720p.mp4
6 | http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4
7 | http://tanzi27niu.cdsb.mobi/wps/wp-content/uploads/2017/05/2017-05-17_17-33-30.mp4
8 | http://9890.vod.myqcloud.com/9890_9c1fa3e2aea011e59fc841df10c92278.f20.mp4
9 | http://ivi.bupt.edu.cn/hls/cctv1hd.m3u8
10 | https://bitdash-a.akamaihd.net/content/MI201109210084_1/m3u8s/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.m3u8
11 | rtsp://184.72.239.149/vod/mp4://BigBuckBunny_175k.mov
12 | rtmp://live.hkstv.hk.lxdns.com/live/hks
13 |
14 |
--------------------------------------------------------------------------------
/lib/src/main/res/layout/lib_player_layout_aplayer.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
15 |
16 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\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 |
--------------------------------------------------------------------------------
/lib/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\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 |
--------------------------------------------------------------------------------
/lib/src/main/res/drawable/lib_player_seekbar_play.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 |
10 | -
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | -
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/d/commenplayer/model/MediaModel.java:
--------------------------------------------------------------------------------
1 | package com.d.commenplayer.model;
2 |
3 | import android.content.Context;
4 |
5 | import com.d.commenplayer.R;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | public class MediaModel {
11 | public String url = "http://vpls.cdn.videojj.com/scene/video02_720p.mp4";
12 | public int position;
13 |
14 | public static List getDatas(Context context, int size) {
15 | final int[] urlResIds = new int[]{
16 | R.string.url1,
17 | R.string.url2,
18 | R.string.url3,
19 | R.string.url4,
20 | R.string.url5,
21 | R.string.url6,
22 | R.string.url7,
23 | R.string.url8,};
24 | final List list = new ArrayList<>();
25 | for (int i = 0; i < size; i++) {
26 | MediaModel model = new MediaModel();
27 | model.url = context.getResources().getString(urlResIds[i % urlResIds.length]);
28 | list.add(model);
29 | }
30 | return list;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 27
5 |
6 | defaultConfig {
7 | applicationId "com.d.commenplayer"
8 | minSdkVersion 14
9 | targetSdkVersion 26
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 | }
15 |
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 |
23 | lintOptions {
24 | abortOnError false
25 | }
26 | }
27 |
28 | dependencies {
29 | testImplementation 'junit:junit:4.12'
30 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
31 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
32 |
33 | implementation fileTree(dir: 'libs', include: ['*.jar'])
34 | implementation project(':lib')
35 |
36 | implementation 'com.android.support:appcompat-v7:27.1.1'
37 | implementation 'com.dsiner.lib:common:1.2.1'
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_simple.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
18 |
19 |
28 |
29 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/d/lib/commenplayer/util/FileMediaDataSource.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer.util;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.io.RandomAccessFile;
6 |
7 | import tv.danmaku.ijk.media.player.misc.IMediaDataSource;
8 |
9 | public class FileMediaDataSource implements IMediaDataSource {
10 | private RandomAccessFile mFile;
11 | private long mFileSize;
12 |
13 | public FileMediaDataSource(File file) throws IOException {
14 | mFile = new RandomAccessFile(file, "r");
15 | mFileSize = mFile.length();
16 | }
17 |
18 | @Override
19 | public int readAt(long position, byte[] buffer, int offset, int size) throws IOException {
20 | if (mFile.getFilePointer() != position)
21 | mFile.seek(position);
22 |
23 | if (size == 0)
24 | return 0;
25 |
26 | return mFile.read(buffer, 0, size);
27 | }
28 |
29 | @Override
30 | public long getSize() throws IOException {
31 | return mFileSize;
32 | }
33 |
34 | @Override
35 | public void close() throws IOException {
36 | mFileSize = 0;
37 | mFile.close();
38 | mFile = null;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
18 |
19 |
23 |
24 |
25 |
31 |
32 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/d/lib/commenplayer/listener/IPlayerListener.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer.listener;
2 |
3 | import tv.danmaku.ijk.media.player.IMediaPlayer;
4 |
5 | /**
6 | * IPlayerListener
7 | * Created by D on 2017/5/28.
8 | */
9 | public interface IPlayerListener {
10 |
11 | void onLoading();
12 |
13 | /**
14 | * Register a callback to be invoked when the end of a media file
15 | * has been reached during playback.
16 | */
17 | void onCompletion(IMediaPlayer mp);
18 |
19 | /**
20 | * Register a callback to be invoked when the media file
21 | * is loaded and ready to go.
22 | */
23 | void onPrepared(IMediaPlayer mp);
24 |
25 | /**
26 | * Register a callback to be invoked when an error occurs
27 | * during playback or setup. If no listener is specified,
28 | * or if the listener returned false, VideoView will inform
29 | * the user of any errors.
30 | */
31 | boolean onError(IMediaPlayer mp, int what, int extra);
32 |
33 | /**
34 | * Register a callback to be invoked when an informational event
35 | * occurs during playback or setup.
36 | */
37 | boolean onInfo(IMediaPlayer mp, int what, int extra);
38 |
39 | void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sarNum, int sarDen);
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/java/com/d/commenplayer/adapter/PlayerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.d.commenplayer.adapter;
2 |
3 | import android.content.Context;
4 | import android.graphics.Color;
5 | import android.widget.ImageView;
6 |
7 | import com.d.commenplayer.R;
8 | import com.d.commenplayer.model.MediaModel;
9 | import com.d.lib.commenplayer.CommenPlayer;
10 | import com.d.lib.commenplayer.listener.OnShowThumbnailListener;
11 | import com.d.lib.pulllayout.rv.adapter.CommonAdapter;
12 | import com.d.lib.pulllayout.rv.adapter.CommonHolder;
13 |
14 | import java.util.List;
15 |
16 | public class PlayerAdapter extends CommonAdapter {
17 | private CommenPlayer mPlayer;
18 |
19 | public PlayerAdapter(Context context, List datas, int layoutId, CommenPlayer player) {
20 | super(context, datas, layoutId);
21 | this.mPlayer = player;
22 | }
23 |
24 | @Override
25 | public void convert(int position, CommonHolder holder, MediaModel item) {
26 | final PlayerItem aplayer = holder.getView(R.id.aplayer);
27 | aplayer.setLive(false);
28 | aplayer.setUrl(item.url);
29 | aplayer.setThumbnail(new OnShowThumbnailListener() {
30 | @Override
31 | public void onShowThumbnail(ImageView ivThumbnail) {
32 | ivThumbnail.setBackgroundColor(Color.parseColor("#303F9F"));
33 | }
34 | });
35 | aplayer.with(mPlayer);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/d/lib/commenplayer/listener/IMediaPlayerControl.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer.listener;
2 |
3 | import android.content.res.Configuration;
4 | import android.widget.MediaController;
5 |
6 | /**
7 | * IMediaPlayerControl
8 | * Created by D on 2017/5/27.
9 | */
10 | public interface IMediaPlayerControl extends MediaController.MediaPlayerControl {
11 |
12 | boolean isLive();
13 |
14 | /**
15 | * Live mode
16 | */
17 | void setLive(boolean live);
18 |
19 | /**
20 | * Control
21 | */
22 | void play(String url);
23 |
24 | String getUrl();
25 |
26 | /**
27 | * Ignore traffic alerts when mobile data
28 | */
29 | void ignoreMobileNet();
30 |
31 | /**
32 | * Display setting
33 | */
34 | void setPlayerVisibility(int visibility);
35 |
36 | void toggleStick();
37 |
38 | void toggleSystemUI(boolean show);
39 |
40 | void lockProgress(boolean lock);
41 |
42 | void progressTo(int position, int bufferPercentage);
43 |
44 | void setScaleType(int scaleType);
45 |
46 | int toggleAspectRatio();
47 |
48 | void onConfigurationChanged(Configuration newConfig);
49 |
50 | void onAnimationUpdate(float factor);
51 |
52 | void toggleOrientation();
53 |
54 | /**
55 | * Life cycle
56 | */
57 | void onResume();
58 |
59 | void onPause();
60 |
61 | boolean onBackPress();
62 |
63 | void onDestroy();
64 | }
65 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
14 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
28 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/lib/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 27
5 |
6 | resourcePrefix 'lib_player_'
7 |
8 | defaultConfig {
9 | minSdkVersion 11
10 | targetSdkVersion 27
11 | versionCode 1
12 | versionName "1.0"
13 | consumerProguardFiles 'consumer-proguard-rules.pro'
14 |
15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 |
25 | lintOptions {
26 | abortOnError false
27 | }
28 | }
29 |
30 | dependencies {
31 | testImplementation 'junit:junit:4.12'
32 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
33 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
34 |
35 | implementation fileTree(dir: 'libs', include: ['*.jar'])
36 |
37 | compileOnly 'com.android.support:support-annotations:27.1.1'
38 |
39 | // Required, enough for most devices.
40 | api 'tv.danmaku.ijk.media:ijkplayer-java:0.7.6'
41 | api 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.7.6'
42 |
43 | // Other ABIs: optional
44 | api 'tv.danmaku.ijk.media:ijkplayer-armv5:0.7.6'
45 | api 'tv.danmaku.ijk.media:ijkplayer-x86:0.7.6'
46 |
47 | // ExoPlayer as IMediaPlayer: optional experimental
48 | api 'tv.danmaku.ijk.media:ijkplayer-exo:0.7.6'
49 | }
50 |
--------------------------------------------------------------------------------
/lib/src/main/res/layout/lib_player_layout_player.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
14 |
15 |
19 |
20 |
25 |
26 |
31 |
32 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/d/lib/commenplayer/services/MediaPlayerService.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer.services;
2 |
3 | import android.app.Service;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.IBinder;
7 | import android.support.annotation.Nullable;
8 |
9 | import com.d.lib.commenplayer.media.MediaManager;
10 |
11 | public class MediaPlayerService extends Service {
12 | private volatile static MediaManager MEDIA_MANAGER;
13 |
14 | public static void intentToStart(Context context) {
15 | context.startService(newIntent(context));
16 | }
17 |
18 | public static void intentToStop(Context context) {
19 | context.stopService(newIntent(context));
20 | }
21 |
22 | private static Intent newIntent(Context context) {
23 | return new Intent(context, MediaPlayerService.class);
24 | }
25 |
26 | public static MediaManager getMediaManager(Context context) {
27 | if (MEDIA_MANAGER == null) {
28 | synchronized (MediaPlayerService.class) {
29 | MEDIA_MANAGER = MediaManager.instance(context);
30 | }
31 | }
32 | return MEDIA_MANAGER;
33 | }
34 |
35 | @Nullable
36 | @Override
37 | public IBinder onBind(Intent intent) {
38 | return null;
39 | }
40 |
41 | @Override
42 | public void onCreate() {
43 | super.onCreate();
44 | }
45 |
46 | @Override
47 | public void onDestroy() {
48 | MEDIA_MANAGER.release(getApplicationContext(), true);
49 | MEDIA_MANAGER = null;
50 | super.onDestroy();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/d/lib/commenplayer/util/Settings.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer.util;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * Preset configuration
7 | */
8 | public class Settings {
9 | public static final int PV_PLAYER__Auto = 0;
10 | public static final int PV_PLAYER__AndroidMediaPlayer = 1;
11 | public static final int PV_PLAYER__IjkMediaPlayer = 2;
12 | public static final int PV_PLAYER__IjkExoMediaPlayer = 3;
13 |
14 | public Settings(Context context) {
15 | }
16 |
17 | public boolean getEnableBackgroundPlay() {
18 | return false;
19 | }
20 |
21 | public int getPlayer() {
22 | return PV_PLAYER__IjkMediaPlayer;
23 | }
24 |
25 | public boolean getUsingMediaCodec() {
26 | return false;
27 | }
28 |
29 | public boolean getUsingMediaCodecAutoRotate() {
30 | return false;
31 | }
32 |
33 | public boolean getMediaCodecHandleResolutionChange() {
34 | return false;
35 | }
36 |
37 | public boolean getUsingOpenSLES() {
38 | return false;
39 | }
40 |
41 | public String getPixelFormat() {
42 | return "";
43 | }
44 |
45 | public boolean getEnableNoView() {
46 | return false;
47 | }
48 |
49 | public boolean getEnableSurfaceView() {
50 | return false;
51 | }
52 |
53 | public boolean getEnableTextureView() {
54 | return true;
55 | }
56 |
57 | public boolean getEnableDetachedSurfaceTextureView() {
58 | return false;
59 | }
60 |
61 | public boolean getUsingMediaDataSource() {
62 | return false;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
17 |
18 |
23 |
24 |
31 |
32 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/d/lib/commenplayer/listener/IRenderView.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer.listener;
2 |
3 | import android.graphics.SurfaceTexture;
4 | import android.support.annotation.NonNull;
5 | import android.support.annotation.Nullable;
6 | import android.view.Surface;
7 | import android.view.SurfaceHolder;
8 | import android.view.View;
9 |
10 | import tv.danmaku.ijk.media.player.IMediaPlayer;
11 |
12 | public interface IRenderView {
13 | int AR_ASPECT_FIT_PARENT = 0; // Without clip
14 | int AR_ASPECT_FILL_PARENT = 1; // May clip
15 | int AR_ASPECT_WRAP_CONTENT = 2;
16 | int AR_MATCH_PARENT = 3;
17 | int AR_16_9_FIT_PARENT = 4;
18 | int AR_4_3_FIT_PARENT = 5;
19 |
20 | View getView();
21 |
22 | boolean shouldWaitForResize();
23 |
24 | void setVideoSize(int videoWidth, int videoHeight);
25 |
26 | void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen);
27 |
28 | void setVideoRotation(int degree);
29 |
30 | void setAspectRatio(int aspectRatio);
31 |
32 | void addRenderCallback(@NonNull IRenderCallback callback);
33 |
34 | void removeRenderCallback(@NonNull IRenderCallback callback);
35 |
36 | interface ISurfaceHolder {
37 | void bindToMediaPlayer(IMediaPlayer mp);
38 |
39 | @NonNull
40 | IRenderView getRenderView();
41 |
42 | @Nullable
43 | SurfaceHolder getSurfaceHolder();
44 |
45 | @Nullable
46 | Surface openSurface();
47 |
48 | @Nullable
49 | SurfaceTexture getSurfaceTexture();
50 | }
51 |
52 | interface IRenderCallback {
53 |
54 | /**
55 | * @param holder Holder
56 | * @param width Could be 0
57 | * @param height Could be 0
58 | */
59 | void onSurfaceCreated(@NonNull ISurfaceHolder holder, int width, int height);
60 |
61 | /**
62 | * @param holder Holder
63 | * @param format Could be 0
64 | * @param width Width
65 | * @param height Height
66 | */
67 | void onSurfaceChanged(@NonNull ISurfaceHolder holder, int format, int width, int height);
68 |
69 | void onSurfaceDestroyed(@NonNull ISurfaceHolder holder);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/d/lib/commenplayer/util/MediaPlayerCompat.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer.util;
2 |
3 | import tv.danmaku.ijk.media.player.IMediaPlayer;
4 | import tv.danmaku.ijk.media.player.IjkMediaPlayer;
5 | import tv.danmaku.ijk.media.player.MediaPlayerProxy;
6 | import tv.danmaku.ijk.media.player.TextureMediaPlayer;
7 |
8 | public class MediaPlayerCompat {
9 |
10 | public static String getName(IMediaPlayer mp) {
11 | if (mp == null) {
12 | return "null";
13 | } else if (mp instanceof TextureMediaPlayer) {
14 | StringBuilder sb = new StringBuilder("TextureMediaPlayer <");
15 | IMediaPlayer internalMediaPlayer = ((TextureMediaPlayer) mp).getInternalMediaPlayer();
16 | if (internalMediaPlayer == null) {
17 | sb.append("null>");
18 | } else {
19 | sb.append(internalMediaPlayer.getClass().getSimpleName());
20 | sb.append(">");
21 | }
22 | return sb.toString();
23 | } else {
24 | return mp.getClass().getSimpleName();
25 | }
26 | }
27 |
28 | public static IjkMediaPlayer getIjkMediaPlayer(IMediaPlayer mp) {
29 | IjkMediaPlayer ijkMediaPlayer = null;
30 | if (mp == null) {
31 | return null;
32 | }
33 | if (mp instanceof IjkMediaPlayer) {
34 | ijkMediaPlayer = (IjkMediaPlayer) mp;
35 | } else if (mp instanceof MediaPlayerProxy && ((MediaPlayerProxy) mp).getInternalMediaPlayer() instanceof IjkMediaPlayer) {
36 | ijkMediaPlayer = (IjkMediaPlayer) ((MediaPlayerProxy) mp).getInternalMediaPlayer();
37 | }
38 | return ijkMediaPlayer;
39 | }
40 |
41 | public static void selectTrack(IMediaPlayer mp, int stream) {
42 | IjkMediaPlayer ijkMediaPlayer = getIjkMediaPlayer(mp);
43 | if (ijkMediaPlayer == null) {
44 | return;
45 | }
46 | ijkMediaPlayer.selectTrack(stream);
47 | }
48 |
49 | public static void deselectTrack(IMediaPlayer mp, int stream) {
50 | IjkMediaPlayer ijkMediaPlayer = getIjkMediaPlayer(mp);
51 | if (ijkMediaPlayer == null) {
52 | return;
53 | }
54 | ijkMediaPlayer.deselectTrack(stream);
55 | }
56 |
57 | public static int getSelectedTrack(IMediaPlayer mp, int trackType) {
58 | IjkMediaPlayer ijkMediaPlayer = getIjkMediaPlayer(mp);
59 | if (ijkMediaPlayer == null) {
60 | return -1;
61 | }
62 | return ijkMediaPlayer.getSelectedTrack(trackType);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/d/lib/commenplayer/util/ULog.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer.util;
2 |
3 | import android.text.TextUtils;
4 | import android.util.Log;
5 |
6 | /**
7 | * Log tool, you can print the log class name, method name, line number
8 | */
9 | public class ULog {
10 |
11 | private static final String LOG_TAG = "ULog";
12 |
13 | /**
14 | * Debug switch
15 | */
16 | private static boolean DEVELOP_MODE = true;
17 |
18 | private ULog() {
19 | }
20 |
21 | public static void setDebug(boolean debug) {
22 | DEVELOP_MODE = debug;
23 | }
24 |
25 | public static void v(String message) {
26 | if (!DEVELOP_MODE || TextUtils.isEmpty(message)) {
27 | return;
28 | }
29 | final StackTraceElement[] stack = new Throwable().getStackTrace();
30 | final int i = 1;
31 | final StackTraceElement ste = stack[i];
32 | Log.println(Log.VERBOSE, LOG_TAG, String.format("[%s][%s][%s]%s", ste.getFileName(), ste.getMethodName(), ste.getLineNumber(), message));
33 | }
34 |
35 | public static void d(String message) {
36 | if (!DEVELOP_MODE || TextUtils.isEmpty(message)) {
37 | return;
38 | }
39 | final StackTraceElement[] stack = new Throwable().getStackTrace();
40 | final int i = 1;
41 | final StackTraceElement ste = stack[i];
42 | Log.println(Log.DEBUG, LOG_TAG, String.format("[%s][%s][%s]%s", ste.getFileName(), ste.getMethodName(), ste.getLineNumber(), message));
43 | }
44 |
45 | public static void i(String message) {
46 | if (!DEVELOP_MODE || TextUtils.isEmpty(message)) {
47 | return;
48 | }
49 | final StackTraceElement[] stack = new Throwable().getStackTrace();
50 | final int i = 1;
51 | final StackTraceElement ste = stack[i];
52 | Log.println(Log.INFO, LOG_TAG, String.format("[%s][%s][%s]%s", ste.getFileName(), ste.getMethodName(), ste.getLineNumber(), message));
53 | }
54 |
55 | public static void w(String message) {
56 | if (!DEVELOP_MODE || TextUtils.isEmpty(message)) {
57 | return;
58 | }
59 | final StackTraceElement[] stack = new Throwable().getStackTrace();
60 | final int i = 1;
61 | final StackTraceElement ste = stack[i];
62 | Log.println(Log.WARN, LOG_TAG, String.format("[%s][%s][%s]%s", ste.getFileName(), ste.getMethodName(), ste.getLineNumber(), message));
63 | }
64 |
65 | public static void e(String message) {
66 | if (!DEVELOP_MODE || TextUtils.isEmpty(message)) {
67 | return;
68 | }
69 | final StackTraceElement[] stack = new Throwable().getStackTrace();
70 | final int i = 1;
71 | final StackTraceElement ste = stack[i];
72 | Log.println(Log.ERROR, LOG_TAG, String.format("[%s][%s][%s]%s", ste.getFileName(), ste.getMethodName(), ste.getLineNumber(), message));
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/app/src/main/java/com/d/commenplayer/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.d.commenplayer;
2 |
3 | import android.Manifest;
4 | import android.content.Intent;
5 | import android.view.View;
6 |
7 | import com.d.commenplayer.activity.ListActivity;
8 | import com.d.commenplayer.activity.SimpleActivity;
9 | import com.d.lib.common.component.mvp.MvpBasePresenter;
10 | import com.d.lib.common.component.mvp.MvpView;
11 | import com.d.lib.common.component.mvp.app.BaseActivity;
12 | import com.d.lib.common.util.ToastUtils;
13 | import com.d.lib.common.util.ViewHelper;
14 | import com.d.lib.permissioncompat.Permission;
15 | import com.d.lib.permissioncompat.PermissionCompat;
16 | import com.d.lib.permissioncompat.PermissionSchedulers;
17 | import com.d.lib.permissioncompat.callback.PermissionCallback;
18 |
19 | public class MainActivity extends BaseActivity>
20 | implements View.OnClickListener {
21 |
22 | @Override
23 | public void onClick(View v) {
24 | switch (v.getId()) {
25 | case R.id.btn_simple:
26 | requestPermission(new Runnable() {
27 | @Override
28 | public void run() {
29 | startActivity(new Intent(mActivity, SimpleActivity.class));
30 | }
31 | });
32 | break;
33 |
34 | case R.id.btn_list:
35 | requestPermission(new Runnable() {
36 | @Override
37 | public void run() {
38 | startActivity(new Intent(mActivity, ListActivity.class));
39 | }
40 | });
41 | break;
42 | }
43 | }
44 |
45 | private void requestPermission(final Runnable runnable) {
46 | PermissionCompat.with(mActivity)
47 | .requestEachCombined(Manifest.permission.READ_EXTERNAL_STORAGE,
48 | Manifest.permission.WRITE_EXTERNAL_STORAGE)
49 | .subscribeOn(PermissionSchedulers.io())
50 | .observeOn(PermissionSchedulers.mainThread())
51 | .requestPermissions(new PermissionCallback() {
52 | @Override
53 | public void onNext(Permission permission) {
54 | if (!permission.granted) {
55 | ToastUtils.toast(getApplicationContext(), "Denied permission!");
56 | return;
57 | }
58 | if (runnable != null) {
59 | runnable.run();
60 | }
61 | }
62 | });
63 | }
64 |
65 | @Override
66 | protected int getLayoutRes() {
67 | return R.layout.activity_main;
68 | }
69 |
70 | @Override
71 | public MvpBasePresenter getPresenter() {
72 | return null;
73 | }
74 |
75 | @Override
76 | protected MvpView getMvpView() {
77 | return null;
78 | }
79 |
80 | @Override
81 | protected void bindView() {
82 | ViewHelper.setOnClickListener(this, this,
83 | R.id.btn_simple,
84 | R.id.btn_list);
85 | }
86 |
87 | @Override
88 | protected void init() {
89 |
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/doc/compile-ijkplayer-zh.md:
--------------------------------------------------------------------------------
1 | # Compile ijkplayer for Android
2 |
3 | ## ijkplayer编译
4 |
5 | ## 环境
6 | - 虚拟机:VirtualBox
7 | - 系统:Ubuntu
8 |
9 | ### 下载 [JDK](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
10 | 下载好的JDK解压到 /home/用户名/Dev/App路径下 (这里的用户名为dsiner) 。解压好后,需要为JDK配置环境变量,右键,打开终端,
11 | 在命令行中键入指令:
12 | ```xml
13 | sudo gedit ~/.bashrc
14 | ```
15 |
16 | 在bashrc文件中加入如下内容:
17 |
18 | ```xml
19 | export JAVA_HOME=/home/dsiner/Dev/App/jdk1.8.0_131
20 | export JRE_HOME=${JAVA_HOME}/jre
21 | export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
22 | export PATH=${JAVA_HOME}/bin:$PATH
23 | ```
24 |
25 | ### 下载 [SDK](https://developer.android.com/studio/index.html)
26 | 下载好的SDK同样解压到了 /home/用户名/Dev/App路径下。解压好后,继续为SDK配置环境变量:
27 | ```xml
28 | export ANDROID_SDK=/home/dsiner/Dev/App/android-sdk-linux
29 | export PATH=${PATH}:$ANDROID_SDK/tools:$ANDROID_SDK/platform-tools
30 | ```
31 |
32 | ### 下载 [NDK](https://dl.google.com/android/repository/android-ndk-r13-linux-x86_64.zip)
33 | 下载好NDK解压在 /home/用户名/Dev/App路径下。解压好后,配置NDK配置环境变量:
34 | ```xml
35 | export ANDROID_NDK=/home/dsiner/Dev/App/android-ndk-r13
36 | export PATH=$PATH:ANDROID_NDK
37 | ```
38 |
39 | ### 使配置生效
40 | source /etc/profile
41 |
42 | ## 编译IJKPlayer
43 | 1. 安装git和yasm,在终端中分别键入:
44 | sudo apt-get install git
45 | sudo apt-get install yasm
46 |
47 | 2. clone ijkplayer 代码
48 | ```xml
49 | cd /home/dsiner/Dev/App
50 | git clone https://github.com/Bilibili/ijkplayer.git
51 | cd /home/dsiner/Dev/App/ijkplayer
52 | git checkout -B k0.7.6
53 | ```
54 |
55 | 3. 切换到config文件夹下,修改module-lite.sh文件
56 | ```xml
57 | export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtp"
58 | export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=tcp"
59 | export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=udp"
60 | export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=rtsp"
61 | export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=sdp"
62 | export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=rtp"
63 | export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=udp"
64 | ```
65 |
66 | 上面的配置只为了支持rtsp和udp,其中rtp是将disable改成了enable。
67 | 另外如果版本>=0.8.2并且没有下面的配置,你可能需要手动添加如下配置以避免编译报错。
68 |
69 | ```xml
70 | export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-linux-perf"
71 | ```
72 |
73 | 然后删除config文件夹下的module.sh,重新创建链接
74 |
75 | ```xml
76 | cd /home/dsiner/Dev/App/ijkplayer/config
77 | rm module.sh
78 | ln -s module-lite module.sh
79 | ```
80 |
81 | ps: module-lite.sh(If you prefer less codec/format for smaller binary size (by default))
82 | module-default.sh(If you prefer more codec/format)
83 | module-lite-hevc.sh(If you prefer less codec/format for smaller binary size (include hevc function))
84 |
85 | 4. 初始化openSSL和FFMPEG
86 | ```xml
87 | cd /home/dsiner/Dev/App/ijkplayer
88 | ./init-android-openssl.sh
89 | ./init-android.sh
90 | ```
91 | ps: 初始化过程似乎主要在下载ffmpeg的代码,代码包比较大,我这边下载速度基本稳定在10kb左右,挂了一晚上才下好......
92 |
93 | 5. 完成编译
94 | ```xml
95 | cd /home/dsiner/Dev/App/ijkplayer/android/contrib
96 | ./compile-openssl.sh clean
97 | ./compile-ffmpeg.sh clean
98 | ./compile-openssl.sh all
99 | ./compile-ffmpeg.sh all
100 |
101 | cd /home/dsiner/Dev/App/ijkplayer/android
102 | ./compile-ijk.sh all
103 | ```
104 |
105 | 6. 在Android项目中设置了rtsp的连接模式为:tcp
106 | ```java
107 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "rtsp_transport", "tcp");
108 | ```
109 |
110 |
--------------------------------------------------------------------------------
/lib/src/main/res/layout/lib_player_layout_touch.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
15 |
16 |
23 |
24 |
33 |
34 |
35 |
36 |
46 |
47 |
51 |
52 |
61 |
62 |
63 |
64 |
74 |
75 |
79 |
80 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/app/src/main/java/com/d/commenplayer/adapter/PlayerItem.java:
--------------------------------------------------------------------------------
1 | package com.d.commenplayer.adapter;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.FrameLayout;
9 | import android.widget.ImageView;
10 |
11 | import com.d.lib.commenplayer.CommenPlayer;
12 | import com.d.lib.commenplayer.R;
13 | import com.d.lib.commenplayer.listener.OnShowThumbnailListener;
14 |
15 | public class PlayerItem extends FrameLayout {
16 | private FrameLayout fl_thumbnail;
17 | private ImageView iv_thumbnail;
18 | private ImageView iv_thumbnail_play;
19 |
20 | private CommenPlayer mPlayer;
21 | private boolean mIsLive;
22 | private String mUrl;
23 |
24 | public PlayerItem(Context context) {
25 | super(context);
26 | init(context);
27 | }
28 |
29 | public PlayerItem(Context context, AttributeSet attrs) {
30 | super(context, attrs);
31 | init(context);
32 | }
33 |
34 | public PlayerItem(Context context, AttributeSet attrs, int defStyleAttr) {
35 | super(context, attrs, defStyleAttr);
36 | init(context);
37 | }
38 |
39 | public static void peelInject(CommenPlayer player, ViewGroup root) {
40 | if (player == null || root == null || player.getParent() == root) {
41 | return;
42 | }
43 | if (player.getParent() != null) {
44 | if (player.getParent() instanceof PlayerItem) {
45 | ((PlayerItem) player.getParent()).recycle(false);
46 | } else {
47 | ((ViewGroup) player.getParent()).removeView(player);
48 | }
49 | }
50 | if (root instanceof PlayerItem) {
51 | ((PlayerItem) root).inject();
52 | } else {
53 | root.removeView(player);
54 | root.addView(player, 0);
55 | }
56 | }
57 |
58 | private void init(Context context) {
59 | View root = LayoutInflater.from(context).inflate(R.layout.lib_player_layout_aplayer, this);
60 | initView(root);
61 | }
62 |
63 | protected void initView(View root) {
64 | fl_thumbnail = (FrameLayout) root.findViewById(R.id.fl_thumbnail);
65 | iv_thumbnail = (ImageView) root.findViewById(R.id.iv_thumbnail);
66 | iv_thumbnail_play = (ImageView) root.findViewById(R.id.iv_thumbnail_play);
67 | fl_thumbnail.setVisibility(VISIBLE);
68 | iv_thumbnail_play.setOnClickListener(new OnClickListener() {
69 | @Override
70 | public void onClick(View v) {
71 | if (mPlayer == null) {
72 | return;
73 | }
74 | mPlayer.pause();
75 | peelInject(mPlayer, PlayerItem.this);
76 | fl_thumbnail.setVisibility(GONE);
77 | mPlayer.play(mUrl);
78 | }
79 | });
80 | }
81 |
82 | public PlayerItem setThumbnail(OnShowThumbnailListener listener) {
83 | if (listener != null) {
84 | listener.onShowThumbnail(iv_thumbnail);
85 | }
86 | return this;
87 | }
88 |
89 | public void with(CommenPlayer player) {
90 | this.mPlayer = player;
91 | }
92 |
93 | public void inject() {
94 | fl_thumbnail.setVisibility(GONE);
95 | if (mPlayer != null) {
96 | removeView(mPlayer);
97 | addView(mPlayer, 0);
98 | }
99 | }
100 |
101 | public void recycle(boolean pause) {
102 | fl_thumbnail.setVisibility(VISIBLE);
103 | if (mPlayer != null) {
104 | if (pause && getChildAt(0) == mPlayer) {
105 | mPlayer.pause();
106 | }
107 | removeView(mPlayer);
108 | }
109 | }
110 |
111 | public void setLive(boolean live) {
112 | this.mIsLive = live;
113 | }
114 |
115 | public void setUrl(String url) {
116 | this.mUrl = url;
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/doc/compile-ijkplayer.md:
--------------------------------------------------------------------------------
1 | # Compile ijkplayer for Android
2 |
3 | ## ijkplayer compilation
4 |
5 | ## Build Environment
6 | - Virtual Machine:VirtualBox
7 | - System:Ubuntu
8 |
9 | ### Download [JDK](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)
10 |
11 | Download the good JDK extract to /home/username/Dev/App path (where the user name is dsiner). After decompression, you need to configure environment variables for the JDK, right-click, open the terminal,Type the command on the command line:
12 | ```xml
13 | sudo gedit ~/.bashrc
14 | ```
15 |
16 | Add the following to the bashrc file:
17 | ```xml
18 | export JAVA_HOME=/home/dsiner/Dev/App/jdk1.8.0_131
19 | export JRE_HOME=${JAVA_HOME}/jre
20 | export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
21 | export PATH=${JAVA_HOME}/bin:$PATH
22 | ```
23 |
24 | ### Download [SDK](https://developer.android.com/studio/index.html)
25 |
26 | The downloaded SDK is also extracted to the /home/username/Dev/App path. After decompression, continue to configure the SDK environment variables:
27 | ```xml
28 | export ANDROID_SDK=/home/dsiner/Dev/App/android-sdk-linux
29 | export PATH=${PATH}:$ANDROID_SDK/tools:$ANDROID_SDK/platform-tools
30 | ```
31 |
32 | ### Download [NDK](https://dl.google.com/android/repository/android-ndk-r13-linux-x86_64.zip)
33 |
34 | Download the NDK to extract the /home/username/Dev/App path. After decompression, configure the NDK configuration environment variable:
35 | ```xml
36 | export ANDROID_NDK=/home/dsiner/Dev/App/android-ndk-r13
37 | export PATH=$PATH:ANDROID_NDK
38 | ```
39 |
40 | ### Make the configuration effective
41 | ```xml
42 | source /etc/profile
43 | ```
44 |
45 | ## Compiling ijkplayer
46 |
47 | 1. Install git and yasm and type in the terminal:
48 | ```xml
49 | sudo apt-get install git
50 | sudo apt-get install yasm
51 | ```
52 |
53 | 2. Clone ijkplayer repertory
54 | ```xml
55 | cd /home/dsiner/Dev/App
56 | git clone https://github.com/Bilibili/ijkplayer.git
57 | cd /home/dsiner/Dev/App/ijkplayer
58 | git checkout -B k0.7.6
59 | ```
60 |
61 | 3. Switch to the config folder and modify the module-lite.sh file
62 | ```xml
63 | export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtp"
64 | export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=tcp"
65 | export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=udp"
66 | export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=rtsp"
67 | export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=sdp"
68 | export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=rtp"
69 | export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=udp"
70 | ```
71 |
72 | ps:
73 | The above configuration is to support rtsp and udp. Where rtp is changed from disable to enable.
74 | If version is greater than 0.8.2 and does not have this configuration, you need to add to avoid compiling error:
75 |
76 | ```xml
77 | export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-linux-perf"
78 | ```
79 |
80 | Then delete the module.sh in the config folder and recreate the link
81 |
82 | ```xml
83 | cd /home/dsiner/Dev/App/ijkplayer/config
84 | rm module.sh
85 | ln -s module-lite module.sh
86 | ```
87 |
88 | ps:
89 | module-lite.sh(If you prefer less codec/format for smaller binary size (by default))
90 | module-default.sh(If you prefer more codec/format)
91 | module-lite-hevc.sh(If you prefer less codec/format for smaller binary size (include hevc function))
92 |
93 | 4. Initialize openSSL and FFMPEG
94 | ```xml
95 | cd /home/dsiner/Dev/App/ijkplayer
96 | ./init-android-openssl.sh
97 | ./init-android.sh
98 | ```
99 |
100 | ps:
101 | The initialization process seems to be mainly download ffmpeg code, the code package is relatively large.
102 |
103 | 5. Complete the compilation
104 | ```xml
105 | cd /home/dsiner/Dev/App/ijkplayer/android/contrib
106 | ./compile-openssl.sh clean
107 | ./compile-ffmpeg.sh clean
108 | ./compile-openssl.sh all
109 | ./compile-ffmpeg.sh all
110 |
111 | cd /home/dsiner/Dev/App/ijkplayer/android
112 | ./compile-ijk.sh all
113 | ```
114 |
115 | 6. The rtsp connection mode is set in the Android project:tcp (Optional)
116 | ```java
117 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "rtsp_transport", "tcp");
118 | ```
119 |
120 |
--------------------------------------------------------------------------------
/README-zh.md:
--------------------------------------------------------------------------------
1 | # CommenPlayer for Android
2 |
3 | [](https://www.apache.org/licenses/LICENSE-2.0)
4 | [](https://android-arsenal.com/api?level=9)
5 |
6 | > 一个适用于 Android 平台的视频播放器,基于ijkplayer、Android MediaPlayer、ExoPlayer / vlc
7 |
8 | ## Branch
9 | - [master](https://github.com/Dsiner/CommenPlayer) - develop分支,依赖形式,支持格式较少、包体积较小,基于 `ijkplayer` ,支持 ijkplayer、Android MediaPlayer、ExoPlayer
10 | - [ijk-lite](https://github.com/Dsiner/CommenPlayer/tree/ijk-lite-v0.8.8) - release分支,.so file,支持格式较少、包体积较小,基于 `ijkplayer` ,支持 ijkplayer、Android MediaPlayer、ExoPlayer
11 | - [ijk-default](https://github.com/Dsiner/CommenPlayer/tree/ijk-default-v0.8.8) - release分支,.so file,支持格式全、包体积较大,基于 `ijkplayer` ,支持 ijkplayer、Android MediaPlayer、ExoPlayer
12 | - [vlc](https://github.com/Dsiner/CommenPlayer/tree/vlc) - beta分支,基于 `vlc`
13 |
14 | ## Demo
15 |
16 |
17 |
18 |
19 | ## Features
20 | - [x] 支持本地和网络视频播放
21 | - [x] 支持 M3U8、RTMP、RTSP、UDP 协议的直播流媒体播放
22 | - [x] 支持常见的音视频文件播放(MP4、mp3、flv等)
23 | - [x] 支持播放控制,进度显示
24 | - [x] 支持手势滑动调节播放进度、亮度、声音
25 | - [x] 支持画面尺寸切换(16:9,4:3,自适应,撑满等)
26 | - [x] 支持横竖屏切换、全屏模式、列表播放、列表播放/全屏模式切换
27 | - [x] 支持全屏沉浸式模式
28 |
29 | ## Usage
30 | ```xml
31 |
35 | ```
36 |
37 | #### Operation
38 | ```java
39 | player.setLive(false);
40 | player.setOnNetListener(new OnNetListener() {
41 | @Override
42 | public void onIgnoreMobileNet() {
43 | ignoreNet = true;
44 | }
45 | }).setOnPlayerListener(new IPlayerListener() {
46 | @Override
47 | public void onLoading() {
48 | player.getControl().setState(ControlLayout.STATE_LOADING);
49 | }
50 |
51 | @Override
52 | public void onCompletion(IMediaPlayer mp) {
53 | player.getControl().setState(ControlLayout.STATE_COMPLETION);
54 | }
55 |
56 | @Override
57 | public void onPrepared(IMediaPlayer mp) {
58 | if (!ignoreNet && NetConstans.NET_STATUS == NetConstans.CONNECTED_MOBILE) {
59 | player.pause();
60 | player.getControl().setState(ControlLayout.STATE_MOBILE_NET);
61 | } else {
62 | player.getControl().setState(ControlLayout.STATE_PREPARED);
63 | }
64 | }
65 |
66 | @Override
67 | public boolean onError(IMediaPlayer mp, int what, int extra) {
68 | player.getControl().setState(ControlLayout.STATE_ERROR);
69 | return false;
70 | }
71 |
72 | @Override
73 | public boolean onInfo(IMediaPlayer mp, int what, int extra) {
74 | return false;
75 | }
76 |
77 | @Override
78 | public void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sarNum, int sarDen) {
79 |
80 | }
81 | });
82 | player.play(url);
83 | ```
84 |
85 | #### Activity Lifecycle
86 | ```java
87 | Override onResume()、onPause()、onConfigurationChanged()、onBackPressed()、onDestroy()
88 | ```
89 |
90 | More usage see [Demo](app/src/main/java/com/d/commenplayer/MainActivity.java)
91 |
92 | ## Latest Changes
93 | - [Changelog.md](CHANGELOG.md)
94 |
95 | ## Thanks
96 | - [ijkplayer](https://github.com/Bilibili/ijkplayer) - Video player based on ffplay
97 | - [vlc-android-sdk](https://github.com/mrmaffen/vlc-android-sdk) - Unofficial VLC Android SDK pushed to JCenter. Supported ABIs are armeabi-v7a, arm64-v8a, x86 and x86_64.
98 | - [JiaoZiVideoPlayer](https://github.com/lipangit/JiaoZiVideoPlayer)
99 | - [NiceVieoPlayer](https://github.com/xiaoyanger0825/NiceVieoPlayer)
100 |
101 | ## Licence
102 |
103 | ```txt
104 | Copyright 2017 D
105 |
106 | Licensed under the Apache License, Version 2.0 (the "License");
107 | you may not use this file except in compliance with the License.
108 | You may obtain a copy of the License at
109 |
110 | http://www.apache.org/licenses/LICENSE-2.0
111 |
112 | Unless required by applicable law or agreed to in writing, software
113 | distributed under the License is distributed on an "AS IS" BASIS,
114 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
115 | See the License for the specific language governing permissions and
116 | limitations under the License.
117 | ```
118 |
--------------------------------------------------------------------------------
/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/src/main/java/com/d/lib/commenplayer/util/Factory.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer.util;
2 |
3 | import android.content.Context;
4 | import android.os.Build;
5 | import android.text.TextUtils;
6 |
7 | import com.d.lib.commenplayer.listener.IRenderView;
8 | import com.d.lib.commenplayer.media.SurfaceRenderView;
9 | import com.d.lib.commenplayer.media.TextureRenderView;
10 |
11 | import java.util.Locale;
12 |
13 | import tv.danmaku.ijk.media.exo.IjkExoMediaPlayer;
14 | import tv.danmaku.ijk.media.player.AndroidMediaPlayer;
15 | import tv.danmaku.ijk.media.player.IMediaPlayer;
16 | import tv.danmaku.ijk.media.player.IjkMediaPlayer;
17 | import tv.danmaku.ijk.media.player.TextureMediaPlayer;
18 |
19 | /**
20 | * Factory
21 | * Created by D on 2017/5/28.
22 | */
23 | public class Factory {
24 | //-------------------------
25 | // Extend: Render
26 | //-------------------------
27 | public static final int RENDER_NONE = 0;
28 | public static final int RENDER_SURFACE_VIEW = 1;
29 | public static final int RENDER_TEXTURE_VIEW = 2;
30 |
31 | public static IRenderView initRenders(Context context) {
32 | int render = RENDER_NONE;
33 | Settings settings = new Settings(context.getApplicationContext());
34 |
35 | if (settings.getEnableTextureView()) {
36 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
37 | render = RENDER_TEXTURE_VIEW;
38 | } else {
39 | render = RENDER_SURFACE_VIEW;
40 | }
41 | } else if (settings.getEnableSurfaceView()) {
42 | render = RENDER_SURFACE_VIEW;
43 | } else if (settings.getEnableNoView()) {
44 | render = RENDER_NONE;
45 | }
46 |
47 | switch (render) {
48 | case RENDER_NONE:
49 | return null;
50 | case RENDER_TEXTURE_VIEW:
51 | return new TextureRenderView(context);
52 | case RENDER_SURFACE_VIEW:
53 | return new SurfaceRenderView(context);
54 | default:
55 | ULog.e(String.format(Locale.getDefault(), "invalid render %d", render));
56 | return null;
57 | }
58 | }
59 |
60 | public static IMediaPlayer createPlayer(Context context, int playerType) {
61 | IMediaPlayer mediaPlayer = null;
62 | Settings mSettings = new Settings(context.getApplicationContext());
63 |
64 | switch (playerType) {
65 | case Settings.PV_PLAYER__IjkExoMediaPlayer: {
66 | IjkExoMediaPlayer IjkExoMediaPlayer = new IjkExoMediaPlayer(context.getApplicationContext());
67 | mediaPlayer = IjkExoMediaPlayer;
68 | }
69 | break;
70 | case Settings.PV_PLAYER__AndroidMediaPlayer: {
71 | AndroidMediaPlayer androidMediaPlayer = new AndroidMediaPlayer();
72 | mediaPlayer = androidMediaPlayer;
73 | }
74 | break;
75 | case Settings.PV_PLAYER__IjkMediaPlayer:
76 | default: {
77 | IjkMediaPlayer ijkMediaPlayer = new IjkMediaPlayer();
78 | ijkMediaPlayer.native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG);
79 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "reconnect", 1);
80 | if (mSettings.getUsingMediaCodec()) {
81 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
82 | if (mSettings.getUsingMediaCodecAutoRotate()) {
83 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1);
84 | } else {
85 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 0);
86 | }
87 | if (mSettings.getMediaCodecHandleResolutionChange()) {
88 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 1);
89 | } else {
90 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 0);
91 | }
92 | } else {
93 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 0);
94 | }
95 |
96 | if (mSettings.getUsingOpenSLES()) {
97 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 1);
98 | } else {
99 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 0);
100 | }
101 |
102 | String pixelFormat = mSettings.getPixelFormat();
103 | if (TextUtils.isEmpty(pixelFormat)) {
104 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", IjkMediaPlayer.SDL_FCC_RV32);
105 | } else {
106 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", pixelFormat);
107 | }
108 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 1);
109 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 1);
110 |
111 | // Set the connection mode of rtsp to: tcp/udp
112 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "rtsp_transport", "tcp");
113 |
114 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "http-detect-range-support", 0);
115 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 48);
116 |
117 | mediaPlayer = ijkMediaPlayer;
118 | }
119 | break;
120 | }
121 |
122 | if (mSettings.getEnableDetachedSurfaceTextureView()) {
123 | mediaPlayer = new TextureMediaPlayer(mediaPlayer);
124 | }
125 |
126 | return mediaPlayer;
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CommenPlayer for Android
2 |
3 | [](https://www.apache.org/licenses/LICENSE-2.0)
4 | [](https://android-arsenal.com/api?level=9)
5 | [](https://github.com/Dsiner/CommenPlayer/blob/master/README-zh.md)
6 |
7 | 
8 |
9 | > Video player for the Android platform based on ijkplayer, Android MediaPlayer, ExoPlayer / Vlc
10 |
11 | ## Branch
12 | - [master](https://github.com/Dsiner/CommenPlayer) - `Develop` branch,dependencies,less codec/format for smaller binary size,base on `ijkplayer` ,support ijkplayer、Android MediaPlayer、ExoPlayer
13 | - [ijkplayer-lite-0.7.6 with .so file](https://github.com/Dsiner/CommenPlayer-ijkplayer/tree/ijk-lite-v0.7.6) - `Release` branch,with .so file,less codec/format for smaller binary size,base on `ijkplayer` ,support ijkplayer、Android MediaPlayer、ExoPlayer
14 | - [ijkplayer-lite-0.8.8 with .so file](https://github.com/Dsiner/CommenPlayer-ijkplayer/tree/ijk-lite-v0.8.8) - `Release` branch,with .so file,less codec/format for smaller binary size,base on `ijkplayer` ,support ijkplayer、Android MediaPlayer、ExoPlayer
15 | - [ijkplayer-default-0.7.6 with .so file](https://github.com/Dsiner/CommenPlayer-ijkplayer/tree/ijk-default-v0.7.6) - `Release` branch,with .so file,more codec/format,base on `ijkplayer` ,support ijkplayer、Android MediaPlayer、ExoPlayer
16 | - [ijkplayer-default-0.8.8 with .so file](https://github.com/Dsiner/CommenPlayer-ijkplayer/tree/ijk-default-v0.8.8) - Release branch,with .so file,more codec/format,base on `ijkplayer` ,support ijkplayer、Android MediaPlayer、ExoPlayer
17 | - [Vlc](https://github.com/Dsiner/CommenPlayer-Vlc) - `Beta` branch,base on `Vlc`
18 |
19 | ## Demo
20 |
21 |
22 |
23 |
24 | ## Features
25 | - [x] Supports local and network video playback
26 | - [x] Live streaming support for M3U8, RTMP, RTSP, UDP protocols
27 | - [x] Supports common audio and video file playback (MP4, mp3, flv, etc.)
28 | - [x] Support playback control, progress display
29 | - [x] Support gestures to adjust playback progress, brightness, sound
30 | - [x] Supports screen size switching (16:9, 4:3, adaptive, full, etc.)
31 | - [x] Supports horizontal and vertical screen switching, full screen mode, list playback, list playback/full screen mode switching
32 | - [x] Supports full screen immersive mode
33 |
34 | ## Usage
35 | ```xml
36 |
40 | ```
41 |
42 | #### Operation
43 | ```java
44 | player.setLive(false);
45 | player.setOnNetListener(new OnNetListener() {
46 | @Override
47 | public void onIgnoreMobileNet() {
48 | ignoreNet = true;
49 | }
50 | }).setOnPlayerListener(new IPlayerListener() {
51 | @Override
52 | public void onLoading() {
53 | player.getControl().setState(ControlLayout.STATE_LOADING);
54 | }
55 |
56 | @Override
57 | public void onCompletion(IMediaPlayer mp) {
58 | player.getControl().setState(ControlLayout.STATE_COMPLETION);
59 | }
60 |
61 | @Override
62 | public void onPrepared(IMediaPlayer mp) {
63 | if (!ignoreNet && NetConstans.NET_STATUS == NetConstans.CONNECTED_MOBILE) {
64 | player.pause();
65 | player.getControl().setState(ControlLayout.STATE_MOBILE_NET);
66 | } else {
67 | player.getControl().setState(ControlLayout.STATE_PREPARED);
68 | }
69 | }
70 |
71 | @Override
72 | public boolean onError(IMediaPlayer mp, int what, int extra) {
73 | player.getControl().setState(ControlLayout.STATE_ERROR);
74 | return false;
75 | }
76 |
77 | @Override
78 | public boolean onInfo(IMediaPlayer mp, int what, int extra) {
79 | return false;
80 | }
81 |
82 | @Override
83 | public void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sarNum, int sarDen) {
84 |
85 | }
86 | });
87 | player.play(url);
88 | ```
89 |
90 | #### Activity Lifecycle
91 | ```java
92 | Override onResume()、onPause()、onConfigurationChanged()、onBackPressed()、onDestroy()
93 | ```
94 |
95 | More usage see [Demo](app/src/main/java/com/d/commenplayer/MainActivity.java)
96 |
97 | ## Latest Changes
98 | - [Changelog.md](CHANGELOG.md)
99 |
100 | ## Contributors
101 | - [Anhar Ismail](https://github.com/anharismail) - Logo design contribution
102 |
103 | ## Thanks
104 | - [ijkplayer](https://github.com/Bilibili/ijkplayer) - Video player based on ffplay
105 | - [vlc-android-sdk](https://github.com/mrmaffen/vlc-android-sdk) - Unofficial VLC Android SDK pushed to JCenter. Supported ABIs are armeabi-v7a, arm64-v8a, x86 and x86_64.
106 | - [JiaoZiVideoPlayer](https://github.com/lipangit/JiaoZiVideoPlayer)
107 | - [NiceVieoPlayer](https://github.com/xiaoyanger0825/NiceVieoPlayer)
108 |
109 | ## Licence
110 |
111 | ```txt
112 | Copyright 2017 D
113 |
114 | Licensed under the Apache License, Version 2.0 (the "License");
115 | you may not use this file except in compliance with the License.
116 | You may obtain a copy of the License at
117 |
118 | http://www.apache.org/licenses/LICENSE-2.0
119 |
120 | Unless required by applicable law or agreed to in writing, software
121 | distributed under the License is distributed on an "AS IS" BASIS,
122 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123 | See the License for the specific language governing permissions and
124 | limitations under the License.
125 | ```
126 |
--------------------------------------------------------------------------------
/lib/src/main/res/layout/lib_player_layout_control.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
17 |
18 |
25 |
26 |
35 |
36 |
37 |
42 |
43 |
49 |
50 |
57 |
58 |
68 |
69 |
84 |
85 |
95 |
96 |
103 |
104 |
105 |
113 |
114 |
121 |
122 |
132 |
133 |
147 |
148 |
149 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/d/lib/commenplayer/util/InfoHudViewHolder.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer.util;
2 |
3 | import android.content.Context;
4 | import android.os.Handler;
5 | import android.os.Message;
6 | import android.widget.TableLayout;
7 |
8 | import java.util.Locale;
9 |
10 | import tv.danmaku.ijk.media.player.IMediaPlayer;
11 | import tv.danmaku.ijk.media.player.IjkMediaPlayer;
12 | import tv.danmaku.ijk.media.player.MediaPlayerProxy;
13 |
14 | /**
15 | * 统计信息
16 | */
17 | public class InfoHudViewHolder {
18 | private static final int MSG_UPDATE_HUD = 1;
19 | private IMediaPlayer mMediaPlayer;
20 | private long mLoadCost = 0;
21 | private long mSeekCost = 0;
22 | private Handler mHandler = new Handler() {
23 | @Override
24 | public void handleMessage(Message msg) {
25 | switch (msg.what) {
26 | case MSG_UPDATE_HUD: {
27 | InfoHudViewHolder holder = InfoHudViewHolder.this;
28 | IjkMediaPlayer mp = null;
29 | if (mMediaPlayer == null)
30 | break;
31 | if (mMediaPlayer instanceof IjkMediaPlayer) {
32 | mp = (IjkMediaPlayer) mMediaPlayer;
33 | } else if (mMediaPlayer instanceof MediaPlayerProxy) {
34 | MediaPlayerProxy proxy = (MediaPlayerProxy) mMediaPlayer;
35 | IMediaPlayer internal = proxy.getInternalMediaPlayer();
36 | if (internal != null && internal instanceof IjkMediaPlayer)
37 | mp = (IjkMediaPlayer) internal;
38 | }
39 | if (mp == null)
40 | break;
41 |
42 | int vdec = mp.getVideoDecoder();
43 | switch (vdec) {
44 | case IjkMediaPlayer.FFP_PROPV_DECODER_AVCODEC:
45 | setRowValue("vdec", "avcodec");
46 | break;
47 | case IjkMediaPlayer.FFP_PROPV_DECODER_MEDIACODEC:
48 | setRowValue("vdec", "MediaCodec");
49 | break;
50 | default:
51 | setRowValue("vdec", "");
52 | break;
53 | }
54 |
55 | float fpsOutput = mp.getVideoOutputFramesPerSecond();
56 | float fpsDecode = mp.getVideoDecodeFramesPerSecond();
57 | setRowValue("fps", String.format(Locale.US, "%.2f / %.2f", fpsDecode, fpsOutput));
58 |
59 | long videoCachedDuration = mp.getVideoCachedDuration();
60 | long audioCachedDuration = mp.getAudioCachedDuration();
61 | long videoCachedBytes = mp.getVideoCachedBytes();
62 | long audioCachedBytes = mp.getAudioCachedBytes();
63 | long tcpSpeed = mp.getTcpSpeed();
64 | long bitRate = mp.getBitRate();
65 | long seekLoadDuration = mp.getSeekLoadDuration();
66 |
67 | setRowValue("v_cache", String.format(Locale.US, "%s, %s", formatedDurationMilli(videoCachedDuration), formatedSize(videoCachedBytes)));
68 | setRowValue("a_cache", String.format(Locale.US, "%s, %s", formatedDurationMilli(audioCachedDuration), formatedSize(audioCachedBytes)));
69 | setRowValue("load_cost", String.format(Locale.US, "%d ms", mLoadCost));
70 | setRowValue("seek_cost", String.format(Locale.US, "%d ms", mSeekCost));
71 | setRowValue("seek_load_cost", String.format(Locale.US, "%d ms", seekLoadDuration));
72 | setRowValue("tcp_speed", String.format(Locale.US, "%s", formatedSpeed(tcpSpeed, 1000)));
73 | setRowValue("bit_rate", String.format(Locale.US, "%.2f kbs", bitRate / 1000f));
74 |
75 | mHandler.removeMessages(MSG_UPDATE_HUD);
76 | mHandler.sendEmptyMessageDelayed(MSG_UPDATE_HUD, 500);
77 | }
78 | }
79 | }
80 | };
81 |
82 | public InfoHudViewHolder(Context context, TableLayout tableLayout) {
83 | }
84 |
85 | private static String formatedDurationMilli(long duration) {
86 | if (duration >= 1000) {
87 | return String.format(Locale.US, "%.2f sec", ((float) duration) / 1000);
88 | } else {
89 | return String.format(Locale.US, "%d msec", duration);
90 | }
91 | }
92 |
93 | private static String formatedSpeed(long bytes, long elapsed_milli) {
94 | if (elapsed_milli <= 0) {
95 | return "0 B/s";
96 | }
97 |
98 | if (bytes <= 0) {
99 | return "0 B/s";
100 | }
101 |
102 | float bytes_per_sec = ((float) bytes) * 1000.f / elapsed_milli;
103 | if (bytes_per_sec >= 1000 * 1000) {
104 | return String.format(Locale.US, "%.2f MB/s", ((float) bytes_per_sec) / 1000 / 1000);
105 | } else if (bytes_per_sec >= 1000) {
106 | return String.format(Locale.US, "%.1f KB/s", ((float) bytes_per_sec) / 1000);
107 | } else {
108 | return String.format(Locale.US, "%d B/s", (long) bytes_per_sec);
109 | }
110 | }
111 |
112 | private static String formatedSize(long bytes) {
113 | if (bytes >= 100 * 1000) {
114 | return String.format(Locale.US, "%.2f MB", ((float) bytes) / 1000 / 1000);
115 | } else if (bytes >= 100) {
116 | return String.format(Locale.US, "%.1f KB", ((float) bytes) / 1000);
117 | } else {
118 | return String.format(Locale.US, "%d B", bytes);
119 | }
120 | }
121 |
122 | private void setRowValue(String id, String value) {
123 | ULog.d("id:" + value);
124 | }
125 |
126 | public void setMediaPlayer(IMediaPlayer mp) {
127 | mMediaPlayer = mp;
128 | if (mMediaPlayer != null) {
129 | mHandler.sendEmptyMessageDelayed(MSG_UPDATE_HUD, 500);
130 | } else {
131 | mHandler.removeMessages(MSG_UPDATE_HUD);
132 | }
133 | }
134 |
135 | public void updateLoadCost(long time) {
136 | mLoadCost = time;
137 | }
138 |
139 | public void updateSeekCost(long time) {
140 | mSeekCost = time;
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/app/src/main/java/com/d/commenplayer/activity/SimpleActivity.java:
--------------------------------------------------------------------------------
1 | package com.d.commenplayer.activity;
2 |
3 | import android.content.Intent;
4 | import android.content.res.Configuration;
5 | import android.support.v4.content.ContextCompat;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 |
9 | import com.d.commenplayer.R;
10 | import com.d.lib.commenplayer.CommenPlayer;
11 | import com.d.lib.commenplayer.listener.IPlayerListener;
12 | import com.d.lib.commenplayer.listener.OnNetworkListener;
13 | import com.d.lib.commenplayer.util.ULog;
14 | import com.d.lib.commenplayer.util.Util;
15 | import com.d.lib.commenplayer.widget.ControlLayout;
16 | import com.d.lib.common.component.mvp.MvpBasePresenter;
17 | import com.d.lib.common.component.mvp.MvpView;
18 | import com.d.lib.common.component.mvp.app.BaseActivity;
19 | import com.d.lib.common.component.network.NetworkBus;
20 | import com.d.lib.common.component.network.NetworkCompat;
21 | import com.d.lib.common.component.statusbarcompat.StatusBarCompat;
22 | import com.d.lib.common.util.NetworkUtils;
23 | import com.d.lib.common.util.ViewHelper;
24 |
25 | import tv.danmaku.ijk.media.player.IMediaPlayer;
26 |
27 | public class SimpleActivity extends BaseActivity>
28 | implements View.OnClickListener {
29 | private CommenPlayer player;
30 | private boolean mIgnoreMobileData;
31 | private NetworkBus.OnNetworkTypeChangeListener mOnNetworkTypeChangeListener;
32 |
33 | @Override
34 | public void onClick(View v) {
35 | switch (v.getId()) {
36 | case R.id.btn_view_history:
37 | startActivity(new Intent(SimpleActivity.this, ListActivity.class));
38 | break;
39 | }
40 | }
41 |
42 | @Override
43 | protected int getLayoutRes() {
44 | return R.layout.activity_simple;
45 | }
46 |
47 | @Override
48 | public MvpBasePresenter getPresenter() {
49 | return null;
50 | }
51 |
52 | @Override
53 | protected MvpView getMvpView() {
54 | return null;
55 | }
56 |
57 | @Override
58 | protected void bindView() {
59 | player = (CommenPlayer) findViewById(R.id.player);
60 |
61 | ViewHelper.setOnClickListener(this, this, R.id.btn_view_history);
62 | }
63 |
64 | @Override
65 | protected void init() {
66 | StatusBarCompat.setStatusBarColor(this,
67 | ContextCompat.getColor(this, R.color.colorBlack));
68 | initPlayer();
69 | mOnNetworkTypeChangeListener = new NetworkBus.OnNetworkTypeChangeListener() {
70 | @Override
71 | public void onNetworkTypeChange(NetworkUtils.NetworkType networkType) {
72 | if (isFinishing()) {
73 | return;
74 | }
75 | ULog.d("dsiner: Network state--> " + networkType);
76 | }
77 | };
78 | NetworkBus.getInstance().addListener(mOnNetworkTypeChangeListener);
79 | }
80 |
81 | private void initPlayer() {
82 | player.setLive(false);
83 | player.setOnNetListener(new OnNetworkListener() {
84 | @Override
85 | public void onIgnoreMobileData() {
86 | mIgnoreMobileData = true;
87 | }
88 | });
89 | player.setOnPlayerListener(new IPlayerListener() {
90 | @Override
91 | public void onLoading() {
92 | player.getControl().setState(ControlLayout.STATE_LOADING);
93 | }
94 |
95 | @Override
96 | public void onCompletion(IMediaPlayer mp) {
97 | player.getControl().setState(ControlLayout.STATE_COMPLETION);
98 | }
99 |
100 | @Override
101 | public void onPrepared(IMediaPlayer mp) {
102 | if (!mIgnoreMobileData
103 | && NetworkCompat.isMobileDataType(NetworkCompat.getType())) {
104 | player.pause();
105 | player.getControl().setState(ControlLayout.STATE_MOBILE_DATA);
106 | } else {
107 | player.getControl().setState(ControlLayout.STATE_PREPARED);
108 | }
109 | }
110 |
111 | @Override
112 | public boolean onError(IMediaPlayer mp, int what, int extra) {
113 | player.getControl().setState(ControlLayout.STATE_ERROR);
114 | return false;
115 | }
116 |
117 | @Override
118 | public boolean onInfo(IMediaPlayer mp, int what, int extra) {
119 | return false;
120 | }
121 |
122 | @Override
123 | public void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sarNum, int sarDen) {
124 |
125 | }
126 | });
127 | player.play(getResources().getString(R.string.url1));
128 | }
129 |
130 | @Override
131 | protected void onResume() {
132 | super.onResume();
133 | if (player != null) {
134 | player.onResume();
135 | }
136 | }
137 |
138 | @Override
139 | protected void onPause() {
140 | if (player != null) {
141 | player.onPause();
142 | }
143 | super.onPause();
144 | }
145 |
146 | @Override
147 | public void onConfigurationChanged(Configuration newConfig) {
148 | super.onConfigurationChanged(newConfig);
149 | final ViewGroup.LayoutParams lp = player.getLayoutParams();
150 | lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
151 | lp.height = newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE
152 | ? ViewGroup.LayoutParams.MATCH_PARENT
153 | : Util.dp2px(getApplicationContext(), 210);
154 | player.setLayoutParams(lp);
155 | if (player != null) {
156 | player.onConfigurationChanged(newConfig);
157 | }
158 | }
159 |
160 | @Override
161 | public void onBackPressed() {
162 | if (player != null && player.onBackPress()) {
163 | return;
164 | }
165 | super.onBackPressed();
166 | }
167 |
168 | @Override
169 | public void finish() {
170 | if (player != null) {
171 | player.onDestroy();
172 | }
173 | super.finish();
174 | }
175 |
176 | @Override
177 | protected void onDestroy() {
178 | NetworkBus.getInstance().removeListener(mOnNetworkTypeChangeListener);
179 | super.onDestroy();
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/d/lib/commenplayer/util/InfoUtil.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer.util;
2 |
3 | import android.content.Context;
4 | import android.text.TextUtils;
5 |
6 | import java.util.Locale;
7 |
8 | import tv.danmaku.ijk.media.player.IMediaPlayer;
9 | import tv.danmaku.ijk.media.player.misc.IMediaFormat;
10 | import tv.danmaku.ijk.media.player.misc.ITrackInfo;
11 | import tv.danmaku.ijk.media.player.misc.IjkMediaFormat;
12 |
13 | /**
14 | * InfoUtil
15 | * Created by D on 2017/5/27.
16 | */
17 | public class InfoUtil {
18 |
19 | //-------------------------
20 | // Extend: Background
21 | //-------------------------
22 | public static void showMediaInfo(Context context, IMediaPlayer mMediaPlayer) {
23 | if (mMediaPlayer == null)
24 | return;
25 |
26 | int mVideoWidth = mMediaPlayer.getVideoWidth();
27 | int mVideoHeight = mMediaPlayer.getVideoHeight();
28 | int mVideoSarNum = mMediaPlayer.getVideoSarNum();
29 | int mVideoSarDen = mMediaPlayer.getVideoSarDen();
30 |
31 | int selectedVideoTrack = MediaPlayerCompat.getSelectedTrack(mMediaPlayer, ITrackInfo.MEDIA_TRACK_TYPE_VIDEO);
32 | int selectedAudioTrack = MediaPlayerCompat.getSelectedTrack(mMediaPlayer, ITrackInfo.MEDIA_TRACK_TYPE_AUDIO);
33 | int selectedSubtitleTrack = MediaPlayerCompat.getSelectedTrack(mMediaPlayer, ITrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT);
34 |
35 | //media_information
36 | ULog.d("Player" + MediaPlayerCompat.getName(mMediaPlayer));
37 | ULog.d("Resolution" + buildResolution(mVideoWidth, mVideoHeight, mVideoSarNum, mVideoSarDen));
38 | ULog.d("Length" + buildTimeMilli(mMediaPlayer.getDuration()));
39 |
40 | ITrackInfo trackInfos[] = mMediaPlayer.getTrackInfo();
41 | if (trackInfos != null) {
42 | int index = -1;
43 | for (ITrackInfo trackInfo : trackInfos) {
44 | index++;
45 |
46 | int trackType = trackInfo.getTrackType();
47 | if (index == selectedVideoTrack) {
48 | ULog.d("Stream #" + index + " mi__selected_video_track");
49 | } else if (index == selectedAudioTrack) {
50 | ULog.d("Stream #" + index + " mi__selected_audio_track");
51 | } else if (index == selectedSubtitleTrack) {
52 | ULog.d("Stream #" + index + " mi__selected_subtitle_track");
53 | } else {
54 | ULog.d("Stream #" + index);
55 | }
56 | ULog.d("Type" + buildTrackType(context, trackType));
57 | String language = TextUtils.isEmpty(trackInfo.getLanguage()) ? "und" : trackInfo.getLanguage();
58 | ULog.d("Language:" + language);
59 |
60 | IMediaFormat mediaFormat = trackInfo.getFormat();
61 | if (mediaFormat == null) {
62 | } else if (mediaFormat instanceof IjkMediaFormat) {
63 | switch (trackType) {
64 | case ITrackInfo.MEDIA_TRACK_TYPE_VIDEO:
65 | ULog.d("Codec:" + mediaFormat.getString(IjkMediaFormat.KEY_IJK_CODEC_LONG_NAME_UI));
66 | ULog.d("Profile level:" + mediaFormat.getString(IjkMediaFormat.KEY_IJK_CODEC_PROFILE_LEVEL_UI));
67 | ULog.d("Pixel format:" + mediaFormat.getString(IjkMediaFormat.KEY_IJK_CODEC_PIXEL_FORMAT_UI));
68 | ULog.d("Resolution:" + mediaFormat.getString(IjkMediaFormat.KEY_IJK_RESOLUTION_UI));
69 | ULog.d("Frame rate:" + mediaFormat.getString(IjkMediaFormat.KEY_IJK_FRAME_RATE_UI));
70 | ULog.d("Bit rate:" + mediaFormat.getString(IjkMediaFormat.KEY_IJK_BIT_RATE_UI));
71 | break;
72 | case ITrackInfo.MEDIA_TRACK_TYPE_AUDIO:
73 | ULog.d("Codec:" + mediaFormat.getString(IjkMediaFormat.KEY_IJK_CODEC_LONG_NAME_UI));
74 | ULog.d("Profile level:" + mediaFormat.getString(IjkMediaFormat.KEY_IJK_CODEC_PROFILE_LEVEL_UI));
75 | ULog.d("Sample rate:" + mediaFormat.getString(IjkMediaFormat.KEY_IJK_SAMPLE_RATE_UI));
76 | ULog.d("Channels:" + mediaFormat.getString(IjkMediaFormat.KEY_IJK_CHANNEL_UI));
77 | ULog.d("Bit rate:" + mediaFormat.getString(IjkMediaFormat.KEY_IJK_BIT_RATE_UI));
78 | break;
79 | default:
80 | break;
81 | }
82 | }
83 | }
84 | }
85 | }
86 |
87 | private static String buildResolution(int width, int height, int sarNum, int sarDen) {
88 | StringBuilder sb = new StringBuilder();
89 | sb.append(width);
90 | sb.append(" x ");
91 | sb.append(height);
92 |
93 | if (sarNum > 1 || sarDen > 1) {
94 | sb.append("[");
95 | sb.append(sarNum);
96 | sb.append(":");
97 | sb.append(sarDen);
98 | sb.append("]");
99 | }
100 |
101 | return sb.toString();
102 | }
103 |
104 | private static String buildTimeMilli(long duration) {
105 | long total_seconds = duration / 1000;
106 | long hours = total_seconds / 3600;
107 | long minutes = (total_seconds % 3600) / 60;
108 | long seconds = total_seconds % 60;
109 | if (duration <= 0) {
110 | return "--:--";
111 | }
112 | if (hours >= 100) {
113 | return String.format(Locale.US, "%d:%02d:%02d", hours, minutes, seconds);
114 | } else if (hours > 0) {
115 | return String.format(Locale.US, "%02d:%02d:%02d", hours, minutes, seconds);
116 | } else {
117 | return String.format(Locale.US, "%02d:%02d", minutes, seconds);
118 | }
119 | }
120 |
121 | private static String buildTrackType(Context context, int type) {
122 | switch (type) {
123 | case ITrackInfo.MEDIA_TRACK_TYPE_VIDEO:
124 | return "TrackType_video";
125 | case ITrackInfo.MEDIA_TRACK_TYPE_AUDIO:
126 | return "TrackType_audio";
127 | case ITrackInfo.MEDIA_TRACK_TYPE_SUBTITLE:
128 | return "TrackType_subtitle";
129 | case ITrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT:
130 | return "TrackType_timedtext";
131 | case ITrackInfo.MEDIA_TRACK_TYPE_METADATA:
132 | return "TrackType_metadata";
133 | case ITrackInfo.MEDIA_TRACK_TYPE_UNKNOWN:
134 | default:
135 | return "TrackType_unknown";
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/app/src/main/java/com/d/commenplayer/activity/ListActivity.java:
--------------------------------------------------------------------------------
1 | package com.d.commenplayer.activity;
2 |
3 | import android.content.res.Configuration;
4 | import android.support.v7.widget.LinearLayoutManager;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.FrameLayout;
9 |
10 | import com.d.commenplayer.R;
11 | import com.d.commenplayer.adapter.PlayerAdapter;
12 | import com.d.commenplayer.adapter.PlayerItem;
13 | import com.d.commenplayer.model.MediaModel;
14 | import com.d.lib.commenplayer.CommenPlayer;
15 | import com.d.lib.commenplayer.listener.IPlayerListener;
16 | import com.d.lib.commenplayer.listener.OnNetworkListener;
17 | import com.d.lib.commenplayer.util.ULog;
18 | import com.d.lib.commenplayer.widget.ControlLayout;
19 | import com.d.lib.common.component.mvp.MvpBasePresenter;
20 | import com.d.lib.common.component.mvp.MvpView;
21 | import com.d.lib.common.component.mvp.app.BaseActivity;
22 | import com.d.lib.common.component.network.NetworkBus;
23 | import com.d.lib.common.component.network.NetworkCompat;
24 | import com.d.lib.common.util.NetworkUtils;
25 | import com.d.lib.common.widget.TitleLayout;
26 | import com.d.lib.pulllayout.rv.adapter.CommonHolder;
27 |
28 | import tv.danmaku.ijk.media.player.IMediaPlayer;
29 |
30 | public class ListActivity extends BaseActivity> {
31 | private ViewGroup mItemContainer;
32 | private TitleLayout tl_title;
33 | private RecyclerView rv_list;
34 | private FrameLayout player_container;
35 |
36 | private CommenPlayer mPlayer;
37 | private boolean mIgnoreMobileData;
38 | private NetworkBus.OnNetworkTypeChangeListener mOnNetworkTypeChangeListener;
39 |
40 | @Override
41 | protected int getLayoutRes() {
42 | return R.layout.activity_list;
43 | }
44 |
45 | @Override
46 | public MvpBasePresenter getPresenter() {
47 | return null;
48 | }
49 |
50 | @Override
51 | protected MvpView getMvpView() {
52 | return null;
53 | }
54 |
55 |
56 | @Override
57 | protected void bindView() {
58 | tl_title = (TitleLayout) findViewById(R.id.tl_title);
59 | rv_list = (RecyclerView) findViewById(R.id.rv_list);
60 | player_container = (FrameLayout) findViewById(R.id.player_container);
61 | }
62 |
63 | @Override
64 | protected void init() {
65 | initPlayer();
66 |
67 | LinearLayoutManager layoutManager = new LinearLayoutManager(this);
68 | layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
69 | rv_list.setLayoutManager(layoutManager);
70 | rv_list.setHasFixedSize(true);
71 | rv_list.setAdapter(new PlayerAdapter(this,
72 | MediaModel.getDatas(this, 20),
73 | R.layout.adapter_player, mPlayer));
74 | rv_list.setRecyclerListener(new RecyclerView.RecyclerListener() {
75 | @Override
76 | public void onViewRecycled(RecyclerView.ViewHolder holder) {
77 | PlayerItem aplayer = ((CommonHolder) holder).getView(R.id.aplayer);
78 | aplayer.recycle(true);
79 | }
80 | });
81 |
82 | mOnNetworkTypeChangeListener = new NetworkBus.OnNetworkTypeChangeListener() {
83 | @Override
84 | public void onNetworkTypeChange(NetworkUtils.NetworkType networkType) {
85 | if (isFinishing()) {
86 | return;
87 | }
88 | ULog.d("dsiner: Network state--> " + networkType);
89 | }
90 | };
91 | NetworkBus.getInstance().addListener(mOnNetworkTypeChangeListener);
92 | }
93 |
94 | private void initPlayer() {
95 | mPlayer = new CommenPlayer(this);
96 | mPlayer.setLive(false);
97 | mPlayer.setOnNetListener(new OnNetworkListener() {
98 | @Override
99 | public void onIgnoreMobileData() {
100 | mIgnoreMobileData = true;
101 | }
102 | });
103 | mPlayer.setOnPlayerListener(new IPlayerListener() {
104 | @Override
105 | public void onLoading() {
106 | mPlayer.getControl().setState(ControlLayout.STATE_LOADING);
107 | }
108 |
109 | @Override
110 | public void onCompletion(IMediaPlayer mp) {
111 | mPlayer.getControl().setState(ControlLayout.STATE_COMPLETION);
112 | }
113 |
114 | @Override
115 | public void onPrepared(IMediaPlayer mp) {
116 | if (!mIgnoreMobileData
117 | && NetworkCompat.isMobileDataType(NetworkCompat.getType())) {
118 | mPlayer.pause();
119 | mPlayer.getControl().setState(ControlLayout.STATE_MOBILE_DATA);
120 | } else {
121 | mPlayer.getControl().setState(ControlLayout.STATE_PREPARED);
122 | }
123 | }
124 |
125 | @Override
126 | public boolean onError(IMediaPlayer mp, int what, int extra) {
127 | mPlayer.getControl().setState(ControlLayout.STATE_ERROR);
128 | return false;
129 | }
130 |
131 | @Override
132 | public boolean onInfo(IMediaPlayer mp, int what, int extra) {
133 | return false;
134 | }
135 |
136 | @Override
137 | public void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sarNum, int sarDen) {
138 |
139 | }
140 | });
141 | }
142 |
143 | @Override
144 | protected void onResume() {
145 | super.onResume();
146 | if (mPlayer != null) {
147 | mPlayer.onResume();
148 | }
149 | }
150 |
151 | @Override
152 | protected void onPause() {
153 | if (mPlayer != null) {
154 | mPlayer.onPause();
155 | }
156 | super.onPause();
157 | }
158 |
159 | @Override
160 | public void onConfigurationChanged(Configuration newConfig) {
161 | super.onConfigurationChanged(newConfig);
162 | if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
163 | player_container.setVisibility(View.VISIBLE);
164 | mItemContainer = (ViewGroup) mPlayer.getParent();
165 | PlayerItem.peelInject(mPlayer, player_container);
166 | } else {
167 | player_container.setVisibility(View.GONE);
168 | PlayerItem.peelInject(mPlayer, mItemContainer);
169 | }
170 | if (mPlayer != null) {
171 | mPlayer.onConfigurationChanged(newConfig);
172 | }
173 | }
174 |
175 | @Override
176 | public void onBackPressed() {
177 | if (mPlayer != null && mPlayer.onBackPress()) {
178 | return;
179 | }
180 | super.onBackPressed();
181 | }
182 |
183 | @Override
184 | public void finish() {
185 | if (mPlayer != null) {
186 | mPlayer.onDestroy();
187 | }
188 | super.finish();
189 | }
190 |
191 | @Override
192 | protected void onDestroy() {
193 | NetworkBus.getInstance().removeListener(mOnNetworkTypeChangeListener);
194 | super.onDestroy();
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/d/lib/commenplayer/media/MeasureHelper.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer.media;
2 |
3 | import android.view.View;
4 |
5 | import com.d.lib.commenplayer.listener.IRenderView;
6 |
7 | import java.lang.ref.WeakReference;
8 |
9 | public final class MeasureHelper {
10 | private WeakReference mWeakView;
11 |
12 | private int mVideoWidth;
13 | private int mVideoHeight;
14 | private int mVideoSarNum;
15 | private int mVideoSarDen;
16 |
17 | private int mVideoRotationDegree;
18 |
19 | private int mMeasuredWidth;
20 | private int mMeasuredHeight;
21 |
22 | private int mCurrentAspectRatio = IRenderView.AR_ASPECT_FIT_PARENT;
23 |
24 | public MeasureHelper(View view) {
25 | mWeakView = new WeakReference(view);
26 | }
27 |
28 | public View getView() {
29 | if (mWeakView == null) {
30 | return null;
31 | }
32 | return mWeakView.get();
33 | }
34 |
35 | public void setVideoSize(int videoWidth, int videoHeight) {
36 | mVideoWidth = videoWidth;
37 | mVideoHeight = videoHeight;
38 | }
39 |
40 | public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) {
41 | mVideoSarNum = videoSarNum;
42 | mVideoSarDen = videoSarDen;
43 | }
44 |
45 | public void setVideoRotation(int videoRotationDegree) {
46 | mVideoRotationDegree = videoRotationDegree;
47 | }
48 |
49 | /**
50 | * Must be called by View.onMeasure(int, int)
51 | */
52 | public void doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
53 | // MLog.i("@@@@onMeasure(" + View.MeasureSpec.toString(widthMeasureSpec) + ", "
54 | // + View.MeasureSpec.toString(heightMeasureSpec) + ")");
55 | if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) {
56 | int tempSpec = widthMeasureSpec;
57 | widthMeasureSpec = heightMeasureSpec;
58 | heightMeasureSpec = tempSpec;
59 | }
60 |
61 | int width = View.getDefaultSize(mVideoWidth, widthMeasureSpec);
62 | int height = View.getDefaultSize(mVideoHeight, heightMeasureSpec);
63 | if (mCurrentAspectRatio == IRenderView.AR_MATCH_PARENT) {
64 | width = widthMeasureSpec;
65 | height = heightMeasureSpec;
66 |
67 | } else if (mVideoWidth > 0 && mVideoHeight > 0) {
68 | int widthSpecMode = View.MeasureSpec.getMode(widthMeasureSpec);
69 | int widthSpecSize = View.MeasureSpec.getSize(widthMeasureSpec);
70 | int heightSpecMode = View.MeasureSpec.getMode(heightMeasureSpec);
71 | int heightSpecSize = View.MeasureSpec.getSize(heightMeasureSpec);
72 |
73 | if (widthSpecMode == View.MeasureSpec.AT_MOST && heightSpecMode == View.MeasureSpec.AT_MOST) {
74 | float specAspectRatio = (float) widthSpecSize / (float) heightSpecSize;
75 | float displayAspectRatio;
76 | switch (mCurrentAspectRatio) {
77 | case IRenderView.AR_16_9_FIT_PARENT:
78 | displayAspectRatio = 16.0f / 9.0f;
79 | if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) {
80 | displayAspectRatio = 1.0f / displayAspectRatio;
81 | }
82 | break;
83 |
84 | case IRenderView.AR_4_3_FIT_PARENT:
85 | displayAspectRatio = 4.0f / 3.0f;
86 | if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) {
87 | displayAspectRatio = 1.0f / displayAspectRatio;
88 | }
89 | break;
90 |
91 | case IRenderView.AR_ASPECT_FIT_PARENT:
92 | case IRenderView.AR_ASPECT_FILL_PARENT:
93 | case IRenderView.AR_ASPECT_WRAP_CONTENT:
94 | default:
95 | displayAspectRatio = (float) mVideoWidth / (float) mVideoHeight;
96 | if (mVideoSarNum > 0 && mVideoSarDen > 0) {
97 | displayAspectRatio = displayAspectRatio * mVideoSarNum / mVideoSarDen;
98 | }
99 | break;
100 | }
101 | final boolean shouldBeWider = displayAspectRatio > specAspectRatio;
102 |
103 | switch (mCurrentAspectRatio) {
104 | case IRenderView.AR_ASPECT_FIT_PARENT:
105 | case IRenderView.AR_16_9_FIT_PARENT:
106 | case IRenderView.AR_4_3_FIT_PARENT:
107 | if (shouldBeWider) {
108 | // too wide, fix width
109 | width = widthSpecSize;
110 | height = (int) (width / displayAspectRatio);
111 | } else {
112 | // too high, fix height
113 | height = heightSpecSize;
114 | width = (int) (height * displayAspectRatio);
115 | }
116 | break;
117 |
118 | case IRenderView.AR_ASPECT_FILL_PARENT:
119 | if (shouldBeWider) {
120 | // not high enough, fix height
121 | height = heightSpecSize;
122 | width = (int) (height * displayAspectRatio);
123 | } else {
124 | // not wide enough, fix width
125 | width = widthSpecSize;
126 | height = (int) (width / displayAspectRatio);
127 | }
128 | break;
129 |
130 | case IRenderView.AR_ASPECT_WRAP_CONTENT:
131 | default:
132 | if (shouldBeWider) {
133 | // too wide, fix width
134 | width = Math.min(mVideoWidth, widthSpecSize);
135 | height = (int) (width / displayAspectRatio);
136 | } else {
137 | // too high, fix height
138 | height = Math.min(mVideoHeight, heightSpecSize);
139 | width = (int) (height * displayAspectRatio);
140 | }
141 | break;
142 | }
143 |
144 | } else if (widthSpecMode == View.MeasureSpec.EXACTLY
145 | && heightSpecMode == View.MeasureSpec.EXACTLY) {
146 | // the size is fixed
147 | width = widthSpecSize;
148 | height = heightSpecSize;
149 |
150 | // for compatibility, we adjust size based on aspect ratio
151 | if (mVideoWidth * height < width * mVideoHeight) {
152 | //Log.i("@@@", "image too wide, correcting");
153 | width = height * mVideoWidth / mVideoHeight;
154 | } else if (mVideoWidth * height > width * mVideoHeight) {
155 | //Log.i("@@@", "image too tall, correcting");
156 | height = width * mVideoHeight / mVideoWidth;
157 | }
158 |
159 | } else if (widthSpecMode == View.MeasureSpec.EXACTLY) {
160 | // only the width is fixed, adjust the height to match aspect ratio if possible
161 | width = widthSpecSize;
162 | height = width * mVideoHeight / mVideoWidth;
163 | if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) {
164 | // couldn't match aspect ratio within the constraints
165 | height = heightSpecSize;
166 | }
167 |
168 | } else if (heightSpecMode == View.MeasureSpec.EXACTLY) {
169 | // only the height is fixed, adjust the width to match aspect ratio if possible
170 | height = heightSpecSize;
171 | width = height * mVideoWidth / mVideoHeight;
172 | if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) {
173 | // couldn't match aspect ratio within the constraints
174 | width = widthSpecSize;
175 | }
176 |
177 | } else {
178 | // neither the width nor the height are fixed, try to use actual video size
179 | width = mVideoWidth;
180 | height = mVideoHeight;
181 | if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) {
182 | // too tall, decrease both width and height
183 | height = heightSpecSize;
184 | width = height * mVideoWidth / mVideoHeight;
185 | }
186 | if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) {
187 | // too wide, decrease both width and height
188 | width = widthSpecSize;
189 | height = width * mVideoHeight / mVideoWidth;
190 | }
191 | }
192 | } else {
193 | // no size yet, just adopt the given spec sizes
194 | }
195 |
196 | mMeasuredWidth = width;
197 | mMeasuredHeight = height;
198 | }
199 |
200 | public int getMeasuredWidth() {
201 | return mMeasuredWidth;
202 | }
203 |
204 | public int getMeasuredHeight() {
205 | return mMeasuredHeight;
206 | }
207 |
208 | public void setAspectRatio(int aspectRatio) {
209 | mCurrentAspectRatio = aspectRatio;
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/d/lib/commenplayer/media/SurfaceRenderView.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer.media;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.graphics.SurfaceTexture;
6 | import android.os.Build;
7 | import android.support.annotation.NonNull;
8 | import android.support.annotation.Nullable;
9 | import android.util.AttributeSet;
10 | import android.view.Surface;
11 | import android.view.SurfaceHolder;
12 | import android.view.SurfaceView;
13 | import android.view.View;
14 | import android.view.accessibility.AccessibilityEvent;
15 | import android.view.accessibility.AccessibilityNodeInfo;
16 |
17 | import com.d.lib.commenplayer.listener.IRenderView;
18 | import com.d.lib.commenplayer.util.ULog;
19 |
20 | import java.lang.ref.WeakReference;
21 | import java.util.Map;
22 | import java.util.concurrent.ConcurrentHashMap;
23 |
24 | import tv.danmaku.ijk.media.player.IMediaPlayer;
25 | import tv.danmaku.ijk.media.player.ISurfaceTextureHolder;
26 |
27 | public class SurfaceRenderView extends SurfaceView implements IRenderView {
28 | private MeasureHelper mMeasureHelper;
29 | private SurfaceCallback mSurfaceCallback;
30 |
31 | public SurfaceRenderView(Context context) {
32 | super(context);
33 | initView(context);
34 | }
35 |
36 | public SurfaceRenderView(Context context, AttributeSet attrs) {
37 | super(context, attrs);
38 | initView(context);
39 | }
40 |
41 | public SurfaceRenderView(Context context, AttributeSet attrs, int defStyleAttr) {
42 | super(context, attrs, defStyleAttr);
43 | initView(context);
44 | }
45 |
46 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
47 | public SurfaceRenderView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
48 | super(context, attrs, defStyleAttr, defStyleRes);
49 | initView(context);
50 | }
51 |
52 | private void initView(Context context) {
53 | mMeasureHelper = new MeasureHelper(this);
54 | mSurfaceCallback = new SurfaceCallback(this);
55 | getHolder().addCallback(mSurfaceCallback);
56 | //noinspection deprecation
57 | getHolder().setType(SurfaceHolder.SURFACE_TYPE_NORMAL);
58 | }
59 |
60 | @Override
61 | public View getView() {
62 | return this;
63 | }
64 |
65 | @Override
66 | public boolean shouldWaitForResize() {
67 | return true;
68 | }
69 |
70 | //--------------------
71 | // Layout & Measure
72 | //--------------------
73 | @Override
74 | public void setVideoSize(int videoWidth, int videoHeight) {
75 | if (videoWidth > 0 && videoHeight > 0) {
76 | mMeasureHelper.setVideoSize(videoWidth, videoHeight);
77 | getHolder().setFixedSize(videoWidth, videoHeight);
78 | requestLayout();
79 | }
80 | }
81 |
82 | @Override
83 | public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) {
84 | if (videoSarNum > 0 && videoSarDen > 0) {
85 | mMeasureHelper.setVideoSampleAspectRatio(videoSarNum, videoSarDen);
86 | requestLayout();
87 | }
88 | }
89 |
90 | @Override
91 | public void setVideoRotation(int degree) {
92 | ULog.e("SurfaceView doesn't support rotation (" + degree + ")!");
93 | }
94 |
95 | @Override
96 | public void setAspectRatio(int aspectRatio) {
97 | mMeasureHelper.setAspectRatio(aspectRatio);
98 | requestLayout();
99 | }
100 |
101 | //--------------------
102 | // SurfaceViewHolder
103 | //--------------------
104 |
105 | @Override
106 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
107 | mMeasureHelper.doMeasure(widthMeasureSpec, heightMeasureSpec);
108 | setMeasuredDimension(mMeasureHelper.getMeasuredWidth(), mMeasureHelper.getMeasuredHeight());
109 | }
110 |
111 | //-------------------------
112 | // SurfaceHolder.Callback
113 | //-------------------------
114 |
115 | @Override
116 | public void addRenderCallback(IRenderCallback callback) {
117 | mSurfaceCallback.addRenderCallback(callback);
118 | }
119 |
120 | @Override
121 | public void removeRenderCallback(IRenderCallback callback) {
122 | mSurfaceCallback.removeRenderCallback(callback);
123 | }
124 |
125 | @Override
126 | public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
127 | super.onInitializeAccessibilityEvent(event);
128 | event.setClassName(SurfaceRenderView.class.getName());
129 | }
130 |
131 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
132 | @Override
133 | public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
134 | super.onInitializeAccessibilityNodeInfo(info);
135 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
136 | info.setClassName(SurfaceRenderView.class.getName());
137 | }
138 | }
139 |
140 | //--------------------
141 | // Accessibility
142 | //--------------------
143 |
144 | private static final class InternalSurfaceHolder implements IRenderView.ISurfaceHolder {
145 | private SurfaceRenderView mSurfaceView;
146 | private SurfaceHolder mSurfaceHolder;
147 |
148 | public InternalSurfaceHolder(@NonNull SurfaceRenderView surfaceView,
149 | @Nullable SurfaceHolder surfaceHolder) {
150 | mSurfaceView = surfaceView;
151 | mSurfaceHolder = surfaceHolder;
152 | }
153 |
154 | public void bindToMediaPlayer(IMediaPlayer mp) {
155 | if (mp != null) {
156 | if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) &&
157 | (mp instanceof ISurfaceTextureHolder)) {
158 | ISurfaceTextureHolder textureHolder = (ISurfaceTextureHolder) mp;
159 | textureHolder.setSurfaceTexture(null);
160 | }
161 | mp.setDisplay(mSurfaceHolder);
162 | }
163 | }
164 |
165 | @NonNull
166 | @Override
167 | public IRenderView getRenderView() {
168 | return mSurfaceView;
169 | }
170 |
171 | @Nullable
172 | @Override
173 | public SurfaceHolder getSurfaceHolder() {
174 | return mSurfaceHolder;
175 | }
176 |
177 | @Nullable
178 | @Override
179 | public SurfaceTexture getSurfaceTexture() {
180 | return null;
181 | }
182 |
183 | @Nullable
184 | @Override
185 | public Surface openSurface() {
186 | if (mSurfaceHolder == null)
187 | return null;
188 | return mSurfaceHolder.getSurface();
189 | }
190 | }
191 |
192 | private static final class SurfaceCallback implements SurfaceHolder.Callback {
193 | private SurfaceHolder mSurfaceHolder;
194 | private boolean mIsFormatChanged;
195 | private int mFormat;
196 | private int mWidth;
197 | private int mHeight;
198 |
199 | private WeakReference mWeakSurfaceView;
200 | private Map mRenderCallbackMap = new ConcurrentHashMap();
201 |
202 | public SurfaceCallback(@NonNull SurfaceRenderView surfaceView) {
203 | mWeakSurfaceView = new WeakReference(surfaceView);
204 | }
205 |
206 | public void addRenderCallback(@NonNull IRenderCallback callback) {
207 | mRenderCallbackMap.put(callback, callback);
208 |
209 | ISurfaceHolder surfaceHolder = null;
210 | if (mSurfaceHolder != null) {
211 | if (surfaceHolder == null)
212 | surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);
213 | callback.onSurfaceCreated(surfaceHolder, mWidth, mHeight);
214 | }
215 |
216 | if (mIsFormatChanged) {
217 | if (surfaceHolder == null)
218 | surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);
219 | callback.onSurfaceChanged(surfaceHolder, mFormat, mWidth, mHeight);
220 | }
221 | }
222 |
223 | public void removeRenderCallback(@NonNull IRenderCallback callback) {
224 | mRenderCallbackMap.remove(callback);
225 | }
226 |
227 | @Override
228 | public void surfaceCreated(SurfaceHolder holder) {
229 | mSurfaceHolder = holder;
230 | mIsFormatChanged = false;
231 | mFormat = 0;
232 | mWidth = 0;
233 | mHeight = 0;
234 |
235 | ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);
236 | for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
237 | renderCallback.onSurfaceCreated(surfaceHolder, 0, 0);
238 | }
239 | }
240 |
241 | @Override
242 | public void surfaceDestroyed(SurfaceHolder holder) {
243 | mSurfaceHolder = null;
244 | mIsFormatChanged = false;
245 | mFormat = 0;
246 | mWidth = 0;
247 | mHeight = 0;
248 |
249 | ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);
250 | for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
251 | renderCallback.onSurfaceDestroyed(surfaceHolder);
252 | }
253 | }
254 |
255 | @Override
256 | public void surfaceChanged(SurfaceHolder holder, int format,
257 | int width, int height) {
258 | mSurfaceHolder = holder;
259 | mIsFormatChanged = true;
260 | mFormat = format;
261 | mWidth = width;
262 | mHeight = height;
263 |
264 | // mMeasureHelper.setVideoSize(width, height);
265 |
266 | ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);
267 | for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
268 | renderCallback.onSurfaceChanged(surfaceHolder, format, width, height);
269 | }
270 | }
271 | }
272 | }
273 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/d/lib/commenplayer/widget/TouchLayout.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer.widget;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.media.AudioManager;
6 | import android.support.annotation.AttrRes;
7 | import android.support.annotation.NonNull;
8 | import android.support.annotation.Nullable;
9 | import android.util.AttributeSet;
10 | import android.view.GestureDetector;
11 | import android.view.LayoutInflater;
12 | import android.view.MotionEvent;
13 | import android.view.View;
14 | import android.view.ViewConfiguration;
15 | import android.view.WindowManager;
16 | import android.widget.FrameLayout;
17 | import android.widget.LinearLayout;
18 | import android.widget.ProgressBar;
19 | import android.widget.TextView;
20 |
21 | import com.d.lib.commenplayer.R;
22 | import com.d.lib.commenplayer.listener.IMediaPlayerControl;
23 | import com.d.lib.commenplayer.util.Util;
24 |
25 | /**
26 | * Video Floating Layer - Sliding Control
27 | * Created by D on 2017/8/8.
28 | */
29 | public class TouchLayout extends FrameLayout implements View.OnTouchListener {
30 | private int TYPE_PROGRESS = 0;
31 | private int TYPE_BRIGHTNESS = 1;
32 | private int TYPE_VOLUME = 2;
33 |
34 | private Activity mActivity;
35 | private int mScreenWidth;
36 | private LinearLayout ll_player_adj_prg;
37 | private TextView tv_player_adj_prg;
38 | private ProgressBar prb_player_adj_prg;
39 | private LinearLayout ll_player_adj_brightness;
40 | private ProgressBar prb_player_adj_brightness;
41 | private LinearLayout ll_player_adj_volume;
42 | private ProgressBar prb_player_adj_volume;
43 | private AudioManager mAudioManager;
44 | private int mTouchSlop;
45 | private boolean mScrollValid;
46 | private boolean mToVolume;
47 | private boolean mToSeek;
48 | private int mPosition;
49 | private int mDuration;
50 | private int mNewPosition = -1;
51 | private int mMaxVolume;
52 | private float mBrightness = -1;
53 | private int mVolume = -1;
54 | private GestureDetector mGestureDetector;
55 | private IMediaPlayerControl mMediaPlayerControl;
56 | private OnGestureListener mOnGestureListener;
57 |
58 | public TouchLayout(@NonNull Context context) {
59 | super(context);
60 | init(context);
61 | }
62 |
63 | public TouchLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
64 | super(context, attrs);
65 | init(context);
66 | }
67 |
68 | public TouchLayout(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
69 | super(context, attrs, defStyleAttr);
70 | init(context);
71 | }
72 |
73 | private void init(Context context) {
74 | mActivity = (Activity) context;
75 | mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
76 | View root = LayoutInflater.from(context).inflate(R.layout.lib_player_layout_touch, this);
77 | initView(root);
78 | int[] size = Util.getScreenSize(mActivity);
79 | mScreenWidth = size[0];
80 | mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
81 | mMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
82 | mGestureDetector = new GestureDetector(context, new PlayerGestureListener());
83 |
84 | root.setClickable(true);
85 | root.setOnTouchListener(this);
86 | }
87 |
88 | private void initView(View root) {
89 | ll_player_adj_prg = (LinearLayout) root.findViewById(R.id.ll_player_adj_prg);
90 | ll_player_adj_brightness = (LinearLayout) root.findViewById(R.id.ll_player_adj_brightness);
91 | ll_player_adj_volume = (LinearLayout) root.findViewById(R.id.ll_player_adj_volume);
92 | tv_player_adj_prg = (TextView) root.findViewById(R.id.tv_player_adj_prg);
93 | prb_player_adj_prg = (ProgressBar) root.findViewById(R.id.prb_player_adj_prg);
94 | prb_player_adj_brightness = (ProgressBar) root.findViewById(R.id.prb_player_adj_brightness);
95 | prb_player_adj_volume = (ProgressBar) root.findViewById(R.id.prb_player_adj_volume);
96 | }
97 |
98 | private void show(int type) {
99 | ll_player_adj_prg.setVisibility(type == TYPE_PROGRESS ? VISIBLE : GONE);
100 | ll_player_adj_brightness.setVisibility(type == TYPE_BRIGHTNESS ? VISIBLE : GONE);
101 | ll_player_adj_volume.setVisibility(type == TYPE_VOLUME ? VISIBLE : GONE);
102 | }
103 |
104 | private void onProgressSlide(float percent) {
105 | if (mMediaPlayerControl == null || mMediaPlayerControl.isLive()) {
106 | return;
107 | }
108 | show(TYPE_PROGRESS);
109 | mNewPosition = (int) (1f * mPosition + 1f * mDuration * percent);
110 | mNewPosition = Math.min(mNewPosition, mDuration);
111 | mNewPosition = Math.max(mNewPosition, 0);
112 | prb_player_adj_prg.setProgress((int) (mNewPosition * 1.0 / mDuration * 100));
113 | tv_player_adj_prg.setText(Util.generateTime(mNewPosition));
114 | mMediaPlayerControl.progressTo(mNewPosition, 0);
115 | }
116 |
117 | /**
118 | * Slide to change brightness
119 | */
120 | private void onBrightnessSlide(float percent) {
121 | show(TYPE_BRIGHTNESS);
122 | if (mBrightness < 0) {
123 | mBrightness = mActivity.getWindow().getAttributes().screenBrightness;
124 | if (mBrightness <= 0.00f) {
125 | mBrightness = 0.50f;
126 | } else if (mBrightness < 0.01f) {
127 | mBrightness = 0.01f;
128 | }
129 | }
130 | WindowManager.LayoutParams lp = mActivity.getWindow().getAttributes();
131 | lp.screenBrightness = mBrightness + percent;
132 | if (lp.screenBrightness > 1.0f) {
133 | lp.screenBrightness = 1.0f;
134 | } else if (lp.screenBrightness < 0.01f) {
135 | lp.screenBrightness = 0.01f;
136 | }
137 | prb_player_adj_brightness.setProgress((int) (lp.screenBrightness * 100));
138 | mActivity.getWindow().setAttributes(lp);
139 | }
140 |
141 | /**
142 | * Slide to adjust the sound size
143 | */
144 | private void onVolumeSlide(float percent) {
145 | show(TYPE_VOLUME);
146 | if (mVolume == -1) {
147 | mVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
148 | if (mVolume < 0) {
149 | mVolume = 0;
150 | }
151 | }
152 | int index = mVolume + (int) (mMaxVolume * percent);
153 | index = Math.min(index, mMaxVolume);
154 | index = Math.max(index, 0);
155 | // Change sound
156 | mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, index, 0);
157 | // Change progress bar
158 | prb_player_adj_volume.setProgress((int) (index * 1.0 / mMaxVolume * 100));
159 | }
160 |
161 | /**
162 | * End of gesture
163 | */
164 | private void endGesture() {
165 | show(GONE);
166 | mVolume = -1;
167 | mBrightness = -1f;
168 | if (mScrollValid && mToSeek && mMediaPlayerControl != null && !mMediaPlayerControl.isLive()) {
169 | mMediaPlayerControl.seekTo(mNewPosition);
170 | mMediaPlayerControl.lockProgress(false);
171 | mScrollValid = false;
172 | }
173 | }
174 |
175 | @Override
176 | public boolean onTouch(View v, MotionEvent event) {
177 | if (mGestureDetector.onTouchEvent(event)) {
178 | return true;
179 | }
180 | // Handling the end of gesture
181 | switch (event.getAction() & MotionEvent.ACTION_MASK) {
182 | case MotionEvent.ACTION_UP:
183 | endGesture();
184 | break;
185 | }
186 | return false;
187 | }
188 |
189 | public void setIMediaPlayerControl(IMediaPlayerControl listener) {
190 | this.mMediaPlayerControl = listener;
191 | }
192 |
193 | public void setOnGestureListener(OnGestureListener l) {
194 | this.mOnGestureListener = l;
195 | }
196 |
197 | public interface OnGestureListener {
198 | void onTouch();
199 | }
200 |
201 | public class PlayerGestureListener extends GestureDetector.SimpleOnGestureListener {
202 | @Override
203 | public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
204 | float oldX = e1.getX(), oldY = e1.getY();
205 | float deltaX = oldX - e2.getX();
206 | float deltaY = oldY - e2.getY();
207 | if (!mScrollValid && (Math.abs(deltaX) > mTouchSlop || Math.abs(deltaY) > mTouchSlop)) {
208 | mToSeek = Math.abs(deltaX) >= Math.abs(deltaY);
209 | mToVolume = oldX > mScreenWidth * 0.5f;
210 | mScrollValid = true; // Sliding takes effect
211 | if (mToSeek && mMediaPlayerControl != null) {
212 | mPosition = mMediaPlayerControl.getCurrentPosition();
213 | mDuration = mMediaPlayerControl.getDuration();
214 | mMediaPlayerControl.lockProgress(true);
215 | }
216 | }
217 | if (mScrollValid) {
218 | if (mToSeek) {
219 | onProgressSlide(-deltaX / getWidth());
220 | } else {
221 | float percent = deltaY / getHeight();
222 | if (mToVolume) {
223 | onVolumeSlide(percent);
224 | } else {
225 | onBrightnessSlide(percent);
226 | }
227 | }
228 | }
229 | return super.onScroll(e1, e2, distanceX, distanceY);
230 | }
231 |
232 | @Override
233 | public boolean onDown(MotionEvent e) {
234 | mScrollValid = false;
235 | if (mOnGestureListener != null) {
236 | mOnGestureListener.onTouch();
237 | }
238 | return super.onDown(e);
239 | }
240 |
241 | @Override
242 | public boolean onDoubleTap(MotionEvent e) {
243 | if (mMediaPlayerControl != null) {
244 | mMediaPlayerControl.toggleAspectRatio();
245 | return true;
246 | }
247 | return true;
248 | }
249 |
250 | @Override
251 | public boolean onSingleTapConfirmed(MotionEvent e) {
252 | if (mMediaPlayerControl != null) {
253 | mMediaPlayerControl.toggleStick();
254 | return true;
255 | }
256 | return super.onSingleTapConfirmed(e);
257 | }
258 | }
259 | }
260 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/d/lib/commenplayer/CommenPlayer.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.pm.ActivityInfo;
6 | import android.content.res.Configuration;
7 | import android.graphics.Bitmap;
8 | import android.os.Build;
9 | import android.os.Handler;
10 | import android.text.TextUtils;
11 | import android.util.AttributeSet;
12 | import android.view.LayoutInflater;
13 | import android.view.View;
14 | import android.widget.FrameLayout;
15 |
16 | import com.d.lib.commenplayer.listener.IMediaPlayerControl;
17 | import com.d.lib.commenplayer.listener.IPlayerListener;
18 | import com.d.lib.commenplayer.listener.IRenderView;
19 | import com.d.lib.commenplayer.listener.OnAnimatorUpdateListener;
20 | import com.d.lib.commenplayer.listener.OnNetworkListener;
21 | import com.d.lib.commenplayer.media.IjkVideoView;
22 | import com.d.lib.commenplayer.media.TextureRenderView;
23 | import com.d.lib.commenplayer.util.Util;
24 | import com.d.lib.commenplayer.widget.ControlLayout;
25 | import com.d.lib.commenplayer.widget.TouchLayout;
26 |
27 | import java.lang.ref.WeakReference;
28 |
29 | /**
30 | * CommenPlayer
31 | * Created by D on 2017/5/27.
32 | */
33 | public class CommenPlayer extends FrameLayout implements IMediaPlayerControl {
34 | private final int TASK_LOOP_TIME = 1000;
35 | private Activity activity;
36 | private IjkVideoView ijkplayer;
37 | private TouchLayout tl_touch;
38 | private ControlLayout cl_control;
39 | private Handler handler = new Handler();
40 | private ProgressTask progressTask;
41 | private boolean progressTaskRunning;
42 | private boolean progressLock; // Progress lock
43 | private boolean live;
44 | private String url;
45 | private boolean isPortrait = true; // true: vertical; false: horizontal
46 | private OnAnimatorUpdateListener animatorUpdateListener; // Stick floating layer, animation
47 | private OnNetworkListener netListener;
48 |
49 | public CommenPlayer(Context context) {
50 | super(context);
51 | init(context);
52 | }
53 |
54 | public CommenPlayer(Context context, AttributeSet attrs) {
55 | super(context, attrs);
56 | init(context);
57 | }
58 |
59 | public CommenPlayer(Context context, AttributeSet attrs, int defStyleAttr) {
60 | super(context, attrs, defStyleAttr);
61 | init(context);
62 | }
63 |
64 | public void reStartProgressTask() {
65 | stopProgressTask();
66 | progressTaskRunning = true;
67 | handler.postDelayed(progressTask, 300);
68 | }
69 |
70 | public void stopProgressTask() {
71 | progressTaskRunning = false;
72 | handler.removeCallbacks(progressTask);
73 | }
74 |
75 | private void init(final Context context) {
76 | activity = (Activity) context;
77 | progressTask = new ProgressTask(this);
78 | View root = LayoutInflater.from(context).inflate(R.layout.lib_player_layout_player, this);
79 | initView(root);
80 | }
81 |
82 | protected void initView(View root) {
83 | ijkplayer = (IjkVideoView) root.findViewById(R.id.ijkplayer);
84 | tl_touch = (TouchLayout) root.findViewById(R.id.tl_touch);
85 | cl_control = (ControlLayout) root.findViewById(R.id.cl_control);
86 | tl_touch.setIMediaPlayerControl(this);
87 | cl_control.setIMediaPlayerControl(this);
88 | }
89 |
90 | public ControlLayout getControl() {
91 | return cl_control;
92 | }
93 |
94 | public TouchLayout getTouch() {
95 | return tl_touch;
96 | }
97 |
98 | @Override
99 | public boolean isLive() {
100 | return live;
101 | }
102 |
103 | @Override
104 | public void setLive(boolean live) {
105 | this.live = live;
106 | ijkplayer.setLive(live);
107 | }
108 |
109 | @Override
110 | public void setScaleType(int scaleType) {
111 | ijkplayer.setScaleType(scaleType);
112 | }
113 |
114 | @Override
115 | public void play(String url) {
116 | play(url, 0);
117 | }
118 |
119 | public void play(String url, int pos) {
120 | if (TextUtils.isEmpty(url)) {
121 | return;
122 | }
123 | this.url = url;
124 | ijkplayer.play(url, pos);
125 | }
126 |
127 | @Override
128 | public String getUrl() {
129 | return url;
130 | }
131 |
132 | public void setUrl(String url) {
133 | this.url = url;
134 | ijkplayer.setVideoPath(url);
135 | }
136 |
137 | @Override
138 | public void ignoreMobileNet() {
139 | if (netListener != null) {
140 | netListener.onIgnoreMobileData();
141 | }
142 | }
143 |
144 | @Override
145 | public void setPlayerVisibility(int visibility) {
146 | ijkplayer.setVisibility(visibility);
147 | }
148 |
149 | @Override
150 | public void toggleStick() {
151 | cl_control.toggleStick();
152 | }
153 |
154 | @Override
155 | public void lockProgress(boolean lock) {
156 | progressLock = lock;
157 | if (progressLock) {
158 | stopProgressTask();
159 | } else {
160 | reStartProgressTask();
161 | }
162 | }
163 |
164 | @Override
165 | public void progressTo(int position, int bufferPercentage) {
166 | cl_control.setProgress(position, getDuration(), bufferPercentage);
167 | }
168 |
169 | @Override
170 | public void seekTo(int pos) {
171 | ijkplayer.seekTo(Math.max(pos, 0));
172 | }
173 |
174 | @Override
175 | public boolean isPlaying() {
176 | return ijkplayer.isPlaying();
177 | }
178 |
179 | @Override
180 | public int getBufferPercentage() {
181 | return ijkplayer.getBufferPercentage();
182 | }
183 |
184 | @Override
185 | public boolean canPause() {
186 | return !live;
187 | }
188 |
189 | @Override
190 | public boolean canSeekBackward() {
191 | return !live;
192 | }
193 |
194 | @Override
195 | public boolean canSeekForward() {
196 | return !live;
197 | }
198 |
199 | @Override
200 | public int getAudioSessionId() {
201 | return 0;
202 | }
203 |
204 | @Override
205 | public void start() {
206 | ijkplayer.start();
207 | }
208 |
209 | @Override
210 | public void pause() {
211 | ijkplayer.pause();
212 | }
213 |
214 | @Override
215 | public int getDuration() {
216 | return ijkplayer.getDuration();
217 | }
218 |
219 | @Override
220 | public int getCurrentPosition() {
221 | return ijkplayer.getCurrentPosition();
222 | }
223 |
224 | @Override
225 | public int toggleAspectRatio() {
226 | return ijkplayer.toggleAspectRatio();
227 | }
228 |
229 | @Override
230 | public void onConfigurationChanged(Configuration newConfig) {
231 | isPortrait = newConfig.orientation != Configuration.ORIENTATION_LANDSCAPE;
232 | if (isPortrait) {
233 | Util.showSystemUIForce(activity, cl_control, tl_touch);
234 | } else {
235 | Util.hideSystemUI(activity, cl_control, tl_touch);
236 | Util.showSystemUI(activity, cl_control, tl_touch);
237 | }
238 | tl_touch.setVisibility(isPortrait ? GONE : VISIBLE);
239 | cl_control.onConfigurationChanged(isPortrait);
240 | setScaleType(IRenderView.AR_ASPECT_FIT_PARENT);
241 | }
242 |
243 | @Override
244 | public void toggleSystemUI(boolean show) {
245 | if (show) {
246 | Util.showSystemUI(activity, cl_control, tl_touch);
247 | } else {
248 | Util.hideSystemUI(activity, cl_control, tl_touch);
249 | }
250 | }
251 |
252 | @Override
253 | public void onAnimationUpdate(float factor) {
254 | if (animatorUpdateListener != null) {
255 | animatorUpdateListener.onAnimationUpdate(factor);
256 | }
257 | }
258 |
259 | @Override
260 | public void toggleOrientation() {
261 | activity.setRequestedOrientation(isPortrait ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
262 | : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
263 | }
264 |
265 | @Override
266 | public void onResume() {
267 | ijkplayer.onResume();
268 | reStartProgressTask();
269 | }
270 |
271 | @Override
272 | public void onPause() {
273 | stopProgressTask();
274 | ijkplayer.onPause();
275 | }
276 |
277 | @Override
278 | public boolean onBackPress() {
279 | if (!isPortrait) {
280 | activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
281 | return true;
282 | }
283 | return false;
284 | }
285 |
286 | @Override
287 | public void onDestroy() {
288 | ijkplayer.onDestroy();
289 | }
290 |
291 | public CommenPlayer setOnPlayerListener(IPlayerListener listener) {
292 | this.ijkplayer.setOnPlayerListener(listener);
293 | return this;
294 | }
295 |
296 | public CommenPlayer setOnAnimatorUpdateListener(OnAnimatorUpdateListener listener) {
297 | this.animatorUpdateListener = listener;
298 | return this;
299 | }
300 |
301 | public CommenPlayer setOnNetListener(OnNetworkListener listener) {
302 | this.netListener = listener;
303 | return this;
304 | }
305 |
306 | /**
307 | * Get a screenshot of the video
308 | */
309 | public Bitmap getSnapShot() {
310 | IRenderView renderView = ijkplayer.getRenderView();
311 | if (renderView == null) {
312 | return null;
313 | }
314 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH
315 | && renderView instanceof TextureRenderView) {
316 | return ((TextureRenderView) renderView).getBitmap();
317 | }
318 | return Util.getFrameAtTime(activity, url, getCurrentPosition());
319 | }
320 |
321 | private static class ProgressTask implements Runnable {
322 | private final WeakReference reference;
323 |
324 | ProgressTask(CommenPlayer layout) {
325 | this.reference = new WeakReference<>(layout);
326 | }
327 |
328 | @Override
329 | public void run() {
330 | CommenPlayer layout = reference.get();
331 | if (layout == null || layout.getContext() == null || !layout.progressTaskRunning || layout.live) {
332 | return;
333 | }
334 | if (!layout.progressLock) {
335 | layout.progressTo(layout.getCurrentPosition(), layout.getBufferPercentage());
336 | }
337 | layout.handler.postDelayed(layout.progressTask, layout.TASK_LOOP_TIME);
338 | }
339 | }
340 | }
341 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/d/lib/commenplayer/media/MediaManager.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer.media;
2 |
3 | import android.content.Context;
4 | import android.media.AudioManager;
5 | import android.media.MediaPlayer;
6 | import android.net.Uri;
7 | import android.os.Build;
8 | import android.os.Handler;
9 | import android.os.Looper;
10 | import android.text.TextUtils;
11 | import android.widget.MediaController;
12 |
13 | import com.d.lib.commenplayer.listener.IPlayerListener;
14 | import com.d.lib.commenplayer.util.Factory;
15 | import com.d.lib.commenplayer.util.FileMediaDataSource;
16 | import com.d.lib.commenplayer.util.Settings;
17 | import com.d.lib.commenplayer.util.ULog;
18 |
19 | import java.io.File;
20 | import java.util.Map;
21 |
22 | import tv.danmaku.ijk.media.player.IMediaPlayer;
23 | import tv.danmaku.ijk.media.player.misc.IMediaDataSource;
24 |
25 | public class MediaManager implements MediaController.MediaPlayerControl,
26 | IMediaPlayer.OnPreparedListener, IMediaPlayer.OnCompletionListener,
27 | IMediaPlayer.OnBufferingUpdateListener, IMediaPlayer.OnSeekCompleteListener,
28 | IMediaPlayer.OnErrorListener, IMediaPlayer.OnVideoSizeChangedListener,
29 | IMediaPlayer.OnInfoListener {
30 |
31 | // All possible internal states
32 | public static final int STATE_ERROR = -1;
33 | public static final int STATE_IDLE = 0;
34 | public static final int STATE_PREPARING = 1;
35 | public static final int STATE_PREPARED = 2;
36 | public static final int STATE_PLAYING = 3;
37 | public static final int STATE_PAUSED = 4;
38 | public static final int STATE_PLAYBACK_COMPLETED = 5;
39 |
40 | private static MediaManager INSTANCE;
41 | // mCurrentState is a VideoView object's current state.
42 | // mTargetState is the state that a method caller intends to reach.
43 | // For instance, regardless the VideoView object's current state,
44 | // calling pause() intends to bring the object to a target state
45 | // of STATE_PAUSED.
46 | public int mCurrentState = STATE_IDLE;
47 | public int mTargetState = STATE_IDLE;
48 | public int mSeekWhenPrepared; // Recording the seek position while preparing
49 | private Settings mSettings;
50 | private Handler mHandler;
51 | private IMediaPlayer mMediaPlayer;
52 | private int mCurrentBufferPercentage;
53 | private IPlayerListener mPlayerListener;
54 |
55 | private MediaManager(Context context) {
56 | mSettings = new Settings(context.getApplicationContext());
57 | mHandler = new Handler(Looper.getMainLooper());
58 | }
59 |
60 | public static MediaManager instance(Context context) {
61 | if (INSTANCE == null) {
62 | synchronized (MediaManager.class) {
63 | INSTANCE = new MediaManager(context.getApplicationContext());
64 | }
65 | }
66 | return INSTANCE;
67 | }
68 |
69 | public void setListener(IPlayerListener listener) {
70 | this.mPlayerListener = listener;
71 | }
72 |
73 | public IMediaPlayer prepare(final Context context,
74 | final Uri uri,
75 | final Map heads,
76 | final boolean looping) {
77 | if (context == null || uri == null) {
78 | return null;
79 | }
80 | mCurrentState = STATE_PREPARING;
81 | mCurrentBufferPercentage = 0;
82 | mSeekWhenPrepared = 0;
83 | // We shouldn't clear the target state, because somebody might have
84 | // called start() previously
85 | release(context, false);
86 | AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
87 | // AudioManager.AUDIOFOCUS_GAIN / AudioManager.AUDIOFOCUS_GAIN_TRANSIENT
88 | am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
89 | try {
90 | mMediaPlayer = Factory.createPlayer(context, mSettings.getPlayer());
91 | if (mMediaPlayer == null) {
92 | return null;
93 | }
94 | mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
95 | String scheme = uri.getScheme();
96 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
97 | && mSettings.getUsingMediaDataSource()
98 | && (TextUtils.isEmpty(scheme) || scheme.equalsIgnoreCase("file"))) {
99 | IMediaDataSource dataSource = new FileMediaDataSource(new File(uri.toString()));
100 | mMediaPlayer.setDataSource(dataSource);
101 |
102 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
103 | mMediaPlayer.setDataSource(context, uri, heads);
104 |
105 | } else {
106 | mMediaPlayer.setDataSource(uri.toString());
107 | }
108 | mMediaPlayer.setLooping(looping);
109 | mMediaPlayer.setOnPreparedListener(this);
110 | mMediaPlayer.setOnCompletionListener(this);
111 | mMediaPlayer.setOnBufferingUpdateListener(this);
112 | mMediaPlayer.setScreenOnWhilePlaying(true);
113 | mMediaPlayer.setOnSeekCompleteListener(this);
114 | mMediaPlayer.setOnErrorListener(this);
115 | mMediaPlayer.setOnInfoListener(this);
116 | mMediaPlayer.setOnVideoSizeChangedListener(this);
117 | mMediaPlayer.prepareAsync();
118 | return mMediaPlayer;
119 | } catch (Exception e) {
120 | ULog.w("Unable to open content: " + uri + e);
121 | onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
122 | e.printStackTrace();
123 | return null;
124 | }
125 | }
126 |
127 | public void release(Context context, boolean clearTargetState) {
128 | if (mMediaPlayer != null) {
129 | mMediaPlayer.stop();
130 | mMediaPlayer.reset();
131 | mMediaPlayer.release();
132 | mMediaPlayer = null;
133 | }
134 | mCurrentState = STATE_IDLE;
135 | if (clearTargetState) {
136 | mTargetState = STATE_IDLE;
137 | }
138 | AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
139 | am.abandonAudioFocus(null);
140 | }
141 |
142 | @Override
143 | public void onPrepared(final IMediaPlayer mp) {
144 | mCurrentState = STATE_PREPARED;
145 | // mSeekWhenPrepared may be changed after seekTo() call
146 | if (mSeekWhenPrepared != 0) {
147 | seekTo(mSeekWhenPrepared);
148 | }
149 | if (mPlayerListener != null) {
150 | mHandler.post(new Runnable() {
151 | @Override
152 | public void run() {
153 | if (mPlayerListener != null)
154 | mPlayerListener.onPrepared(mp);
155 | }
156 | });
157 | }
158 | }
159 |
160 | @Override
161 | public void onCompletion(final IMediaPlayer mp) {
162 | mCurrentState = STATE_PLAYBACK_COMPLETED;
163 | mTargetState = STATE_PLAYBACK_COMPLETED;
164 | if (mPlayerListener != null) {
165 | mHandler.post(new Runnable() {
166 | @Override
167 | public void run() {
168 | if (mPlayerListener != null)
169 | mPlayerListener.onCompletion(mp);
170 | }
171 | });
172 | }
173 | }
174 |
175 | @Override
176 | public void onBufferingUpdate(IMediaPlayer mp, final int percent) {
177 | mCurrentBufferPercentage = percent;
178 | }
179 |
180 | @Override
181 | public void onSeekComplete(IMediaPlayer mp) {
182 | }
183 |
184 | @Override
185 | public boolean onError(final IMediaPlayer mp, final int what, final int extra) {
186 | ULog.d("Error: " + what + "," + extra);
187 | if (what == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
188 | ULog.d("onError:" + "Invalid progressive playback");
189 | } else {
190 | ULog.d("onError:" + "Unknown");
191 | }
192 | mCurrentState = STATE_ERROR;
193 | mTargetState = STATE_ERROR;
194 | /* If an error handler has been supplied, use it and finish. */
195 | if (mPlayerListener != null) {
196 | mHandler.post(new Runnable() {
197 | @Override
198 | public void run() {
199 | if (mPlayerListener == null) {
200 | return;
201 | }
202 | mPlayerListener.onError(mp, what, extra);
203 | }
204 | });
205 | return true;
206 | }
207 | return false;
208 | }
209 |
210 | @Override
211 | public boolean onInfo(final IMediaPlayer mp, final int what, final int extra) {
212 | if (mPlayerListener != null) {
213 | mHandler.post(new Runnable() {
214 | @Override
215 | public void run() {
216 | if (mPlayerListener == null) {
217 | return;
218 | }
219 | mPlayerListener.onInfo(mp, what, extra);
220 | }
221 | });
222 | return true;
223 | }
224 | return false;
225 | }
226 |
227 | @Override
228 | public void onVideoSizeChanged(final IMediaPlayer mp, final int width, final int height, final int sarNum, final int sarDen) {
229 | if (mPlayerListener != null) {
230 | mHandler.post(new Runnable() {
231 | @Override
232 | public void run() {
233 | if (mPlayerListener == null) {
234 | return;
235 | }
236 | mPlayerListener.onVideoSizeChanged(mp, width, height, sarNum, sarDen);
237 | }
238 | });
239 | }
240 | }
241 |
242 | @Override
243 | public void start() {
244 | if (isInPlaybackState()) {
245 | mMediaPlayer.start();
246 | mCurrentState = STATE_PLAYING;
247 | }
248 | mTargetState = STATE_PLAYING;
249 | }
250 |
251 | @Override
252 | public void pause() {
253 | if (isInPlaybackState()) {
254 | mMediaPlayer.pause();
255 | mCurrentState = STATE_PAUSED;
256 | }
257 | mTargetState = STATE_PAUSED;
258 | }
259 |
260 | @Override
261 | public int getDuration() {
262 | if (isInPlaybackState()) {
263 | return (int) mMediaPlayer.getDuration();
264 | }
265 | return -1;
266 | }
267 |
268 | @Override
269 | public int getCurrentPosition() {
270 | if (isInPlaybackState()) {
271 | return (int) mMediaPlayer.getCurrentPosition();
272 | }
273 | return 0;
274 | }
275 |
276 | @Override
277 | public void seekTo(int msec) {
278 | if (isInPlaybackState()) {
279 | mMediaPlayer.seekTo(msec);
280 | mSeekWhenPrepared = 0;
281 | } else {
282 | mSeekWhenPrepared = msec;
283 | }
284 | }
285 |
286 | @Override
287 | public boolean isPlaying() {
288 | return isInPlaybackState() && mMediaPlayer.isPlaying();
289 | }
290 |
291 | @Override
292 | public int getBufferPercentage() {
293 | return mCurrentBufferPercentage;
294 | }
295 |
296 | @Override
297 | public boolean canPause() {
298 | return false;
299 | }
300 |
301 | @Override
302 | public boolean canSeekBackward() {
303 | return false;
304 | }
305 |
306 | @Override
307 | public boolean canSeekForward() {
308 | return false;
309 | }
310 |
311 | @Override
312 | public int getAudioSessionId() {
313 | return 0;
314 | }
315 |
316 | private boolean isInPlaybackState() {
317 | return (mMediaPlayer != null
318 | && mCurrentState != STATE_ERROR
319 | && mCurrentState != STATE_IDLE
320 | && mCurrentState != STATE_PREPARING);
321 | }
322 | }
323 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/d/lib/commenplayer/media/TextureRenderView.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer.media;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.graphics.SurfaceTexture;
6 | import android.os.Build;
7 | import android.support.annotation.NonNull;
8 | import android.support.annotation.Nullable;
9 | import android.util.AttributeSet;
10 | import android.view.Surface;
11 | import android.view.SurfaceHolder;
12 | import android.view.TextureView;
13 | import android.view.View;
14 | import android.view.accessibility.AccessibilityEvent;
15 | import android.view.accessibility.AccessibilityNodeInfo;
16 |
17 | import com.d.lib.commenplayer.listener.IRenderView;
18 | import com.d.lib.commenplayer.util.ULog;
19 |
20 | import java.lang.ref.WeakReference;
21 | import java.util.Map;
22 | import java.util.concurrent.ConcurrentHashMap;
23 |
24 | import tv.danmaku.ijk.media.player.IMediaPlayer;
25 | import tv.danmaku.ijk.media.player.ISurfaceTextureHolder;
26 | import tv.danmaku.ijk.media.player.ISurfaceTextureHost;
27 |
28 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
29 | public class TextureRenderView extends TextureView implements IRenderView {
30 | private MeasureHelper mMeasureHelper;
31 | private SurfaceCallback mSurfaceCallback;
32 |
33 | public TextureRenderView(Context context) {
34 | super(context);
35 | initView(context);
36 | }
37 |
38 | public TextureRenderView(Context context, AttributeSet attrs) {
39 | super(context, attrs);
40 | initView(context);
41 | }
42 |
43 | public TextureRenderView(Context context, AttributeSet attrs, int defStyleAttr) {
44 | super(context, attrs, defStyleAttr);
45 | initView(context);
46 | }
47 |
48 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
49 | public TextureRenderView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
50 | super(context, attrs, defStyleAttr, defStyleRes);
51 | initView(context);
52 | }
53 |
54 | private void initView(Context context) {
55 | mMeasureHelper = new MeasureHelper(this);
56 | mSurfaceCallback = new SurfaceCallback(this);
57 | setSurfaceTextureListener(mSurfaceCallback);
58 | }
59 |
60 | @Override
61 | public View getView() {
62 | return this;
63 | }
64 |
65 | @Override
66 | public boolean shouldWaitForResize() {
67 | return false;
68 | }
69 |
70 | @Override
71 | protected void onDetachedFromWindow() {
72 | mSurfaceCallback.willDetachFromWindow();
73 | super.onDetachedFromWindow();
74 | mSurfaceCallback.didDetachFromWindow();
75 | }
76 |
77 | //--------------------
78 | // Layout & Measure
79 | //--------------------
80 | @Override
81 | public void setVideoSize(int videoWidth, int videoHeight) {
82 | if (videoWidth > 0 && videoHeight > 0) {
83 | mMeasureHelper.setVideoSize(videoWidth, videoHeight);
84 | requestLayout();
85 | }
86 | }
87 |
88 | @Override
89 | public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) {
90 | if (videoSarNum > 0 && videoSarDen > 0) {
91 | mMeasureHelper.setVideoSampleAspectRatio(videoSarNum, videoSarDen);
92 | requestLayout();
93 | }
94 | }
95 |
96 | @Override
97 | public void setVideoRotation(int degree) {
98 | mMeasureHelper.setVideoRotation(degree);
99 | setRotation(degree);
100 | }
101 |
102 | @Override
103 | public void setAspectRatio(int aspectRatio) {
104 | mMeasureHelper.setAspectRatio(aspectRatio);
105 | requestLayout();
106 | }
107 |
108 | //--------------------
109 | // TextureViewHolder
110 | //--------------------
111 |
112 | @Override
113 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
114 | mMeasureHelper.doMeasure(widthMeasureSpec, heightMeasureSpec);
115 | setMeasuredDimension(mMeasureHelper.getMeasuredWidth(), mMeasureHelper.getMeasuredHeight());
116 | }
117 |
118 | public IRenderView.ISurfaceHolder getSurfaceHolder() {
119 | return new InternalSurfaceHolder(this, mSurfaceCallback.mSurfaceTexture, mSurfaceCallback);
120 | }
121 |
122 | //-------------------------
123 | // SurfaceHolder.Callback
124 | //-------------------------
125 |
126 | @Override
127 | public void addRenderCallback(IRenderCallback callback) {
128 | mSurfaceCallback.addRenderCallback(callback);
129 | }
130 |
131 | @Override
132 | public void removeRenderCallback(IRenderCallback callback) {
133 | mSurfaceCallback.removeRenderCallback(callback);
134 | }
135 |
136 | @Override
137 | public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
138 | super.onInitializeAccessibilityEvent(event);
139 | event.setClassName(TextureRenderView.class.getName());
140 | }
141 |
142 | @Override
143 | public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
144 | super.onInitializeAccessibilityNodeInfo(info);
145 | info.setClassName(TextureRenderView.class.getName());
146 | }
147 |
148 | //--------------------
149 | // Accessibility
150 | //--------------------
151 |
152 | private static final class InternalSurfaceHolder implements IRenderView.ISurfaceHolder {
153 | private TextureRenderView mTextureView;
154 | private SurfaceTexture mSurfaceTexture;
155 | private ISurfaceTextureHost mSurfaceTextureHost;
156 |
157 | public InternalSurfaceHolder(@NonNull TextureRenderView textureView,
158 | @Nullable SurfaceTexture surfaceTexture,
159 | @NonNull ISurfaceTextureHost surfaceTextureHost) {
160 | mTextureView = textureView;
161 | mSurfaceTexture = surfaceTexture;
162 | mSurfaceTextureHost = surfaceTextureHost;
163 | }
164 |
165 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
166 | public void bindToMediaPlayer(IMediaPlayer mp) {
167 | if (mp == null)
168 | return;
169 |
170 | if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) &&
171 | (mp instanceof ISurfaceTextureHolder)) {
172 | ISurfaceTextureHolder textureHolder = (ISurfaceTextureHolder) mp;
173 | mTextureView.mSurfaceCallback.setOwnSurfaceTexture(false);
174 |
175 | SurfaceTexture surfaceTexture = textureHolder.getSurfaceTexture();
176 | if (surfaceTexture != null) {
177 | mTextureView.setSurfaceTexture(surfaceTexture);
178 | } else {
179 | textureHolder.setSurfaceTexture(mSurfaceTexture);
180 | textureHolder.setSurfaceTextureHost(mTextureView.mSurfaceCallback);
181 | }
182 | } else {
183 | mp.setSurface(openSurface());
184 | }
185 | }
186 |
187 | @NonNull
188 | @Override
189 | public IRenderView getRenderView() {
190 | return mTextureView;
191 | }
192 |
193 | @Nullable
194 | @Override
195 | public SurfaceHolder getSurfaceHolder() {
196 | return null;
197 | }
198 |
199 | @Nullable
200 | @Override
201 | public SurfaceTexture getSurfaceTexture() {
202 | return mSurfaceTexture;
203 | }
204 |
205 | @Nullable
206 | @Override
207 | public Surface openSurface() {
208 | if (mSurfaceTexture == null)
209 | return null;
210 | return new Surface(mSurfaceTexture);
211 | }
212 | }
213 |
214 | private static final class SurfaceCallback implements SurfaceTextureListener, ISurfaceTextureHost {
215 | private SurfaceTexture mSurfaceTexture;
216 | private boolean mIsFormatChanged;
217 | private int mWidth;
218 | private int mHeight;
219 |
220 | private boolean mOwnSurfaceTexture = true;
221 | private boolean mWillDetachFromWindow = false;
222 | private boolean mDidDetachFromWindow = false;
223 |
224 | private WeakReference mWeakRenderView;
225 | private Map mRenderCallbackMap = new ConcurrentHashMap();
226 |
227 | public SurfaceCallback(@NonNull TextureRenderView renderView) {
228 | mWeakRenderView = new WeakReference(renderView);
229 | }
230 |
231 | public void setOwnSurfaceTexture(boolean ownSurfaceTexture) {
232 | mOwnSurfaceTexture = ownSurfaceTexture;
233 | }
234 |
235 | public void addRenderCallback(@NonNull IRenderCallback callback) {
236 | mRenderCallbackMap.put(callback, callback);
237 |
238 | ISurfaceHolder surfaceHolder = null;
239 | if (mSurfaceTexture != null) {
240 | if (surfaceHolder == null)
241 | surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), mSurfaceTexture, this);
242 | callback.onSurfaceCreated(surfaceHolder, mWidth, mHeight);
243 | }
244 |
245 | if (mIsFormatChanged) {
246 | if (surfaceHolder == null)
247 | surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), mSurfaceTexture, this);
248 | callback.onSurfaceChanged(surfaceHolder, 0, mWidth, mHeight);
249 | }
250 | }
251 |
252 | public void removeRenderCallback(@NonNull IRenderCallback callback) {
253 | mRenderCallbackMap.remove(callback);
254 | }
255 |
256 | @Override
257 | public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
258 | mSurfaceTexture = surface;
259 | mIsFormatChanged = false;
260 | mWidth = 0;
261 | mHeight = 0;
262 |
263 | ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), surface, this);
264 | for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
265 | renderCallback.onSurfaceCreated(surfaceHolder, 0, 0);
266 | }
267 | }
268 |
269 | @Override
270 | public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
271 | mSurfaceTexture = surface;
272 | mIsFormatChanged = true;
273 | mWidth = width;
274 | mHeight = height;
275 |
276 | ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), surface, this);
277 | for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
278 | renderCallback.onSurfaceChanged(surfaceHolder, 0, width, height);
279 | }
280 | }
281 |
282 | @Override
283 | public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
284 | mSurfaceTexture = surface;
285 | mIsFormatChanged = false;
286 | mWidth = 0;
287 | mHeight = 0;
288 |
289 | ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), surface, this);
290 | for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
291 | renderCallback.onSurfaceDestroyed(surfaceHolder);
292 | }
293 |
294 | ULog.d("onSurfaceTextureDestroyed: destroy: " + mOwnSurfaceTexture);
295 | return mOwnSurfaceTexture;
296 | }
297 |
298 | @Override
299 | public void onSurfaceTextureUpdated(SurfaceTexture surface) {
300 | }
301 |
302 | //-------------------------
303 | // ISurfaceTextureHost
304 | //-------------------------
305 |
306 | @Override
307 | public void releaseSurfaceTexture(SurfaceTexture surfaceTexture) {
308 | if (surfaceTexture == null) {
309 | ULog.d("releaseSurfaceTexture: null");
310 | } else if (mDidDetachFromWindow) {
311 | if (surfaceTexture != mSurfaceTexture) {
312 | ULog.d("releaseSurfaceTexture: didDetachFromWindow(): release different SurfaceTexture");
313 | surfaceTexture.release();
314 | } else if (!mOwnSurfaceTexture) {
315 | ULog.d("releaseSurfaceTexture: didDetachFromWindow(): release detached SurfaceTexture");
316 | surfaceTexture.release();
317 | } else {
318 | ULog.d("releaseSurfaceTexture: didDetachFromWindow(): already released by TextureView");
319 | }
320 | } else if (mWillDetachFromWindow) {
321 | if (surfaceTexture != mSurfaceTexture) {
322 | ULog.d("releaseSuMrfaceTexture: willDetachFromWindow(): release different SurfaceTexture");
323 | surfaceTexture.release();
324 | } else if (!mOwnSurfaceTexture) {
325 | ULog.d("releaseSurfaceTexture: willDetachFromWindow(): re-attach SurfaceTexture to TextureView");
326 | setOwnSurfaceTexture(true);
327 | } else {
328 | ULog.d("releaseSurfaceTexture: willDetachFromWindow(): will released by TextureView");
329 | }
330 | } else {
331 | if (surfaceTexture != mSurfaceTexture) {
332 | ULog.d("releaseSurfaceTexture: alive: release different SurfaceTexture");
333 | surfaceTexture.release();
334 | } else if (!mOwnSurfaceTexture) {
335 | ULog.d("releaseSurfaceTexture: alive: re-attach SurfaceTexture to TextureView");
336 | setOwnSurfaceTexture(true);
337 | } else {
338 | ULog.d("releaseSurfaceTexture: alive: will released by TextureView");
339 | }
340 | }
341 | }
342 |
343 | public void willDetachFromWindow() {
344 | ULog.d("willDetachFromWindow()");
345 | mWillDetachFromWindow = true;
346 | }
347 |
348 | public void didDetachFromWindow() {
349 | ULog.d("didDetachFromWindow()");
350 | mDidDetachFromWindow = true;
351 | }
352 | }
353 | }
354 |
--------------------------------------------------------------------------------
/lib/src/main/java/com/d/lib/commenplayer/media/IjkVideoView.java:
--------------------------------------------------------------------------------
1 | package com.d.lib.commenplayer.media;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.net.Uri;
6 | import android.support.annotation.NonNull;
7 | import android.util.AttributeSet;
8 | import android.view.Gravity;
9 | import android.view.View;
10 | import android.widget.FrameLayout;
11 | import android.widget.MediaController;
12 |
13 | import com.d.lib.commenplayer.listener.IPlayerListener;
14 | import com.d.lib.commenplayer.listener.IRenderView;
15 | import com.d.lib.commenplayer.services.MediaPlayerService;
16 | import com.d.lib.commenplayer.util.Factory;
17 | import com.d.lib.commenplayer.util.Settings;
18 | import com.d.lib.commenplayer.util.ULog;
19 |
20 | import java.util.Map;
21 |
22 | import tv.danmaku.ijk.media.player.IMediaPlayer;
23 | import tv.danmaku.ijk.media.player.IjkMediaPlayer;
24 |
25 | public class IjkVideoView extends FrameLayout
26 | implements MediaController.MediaPlayerControl, IPlayerListener {
27 |
28 | private static final int[] ALL_ASPECT_RATIO = {
29 | IRenderView.AR_ASPECT_FIT_PARENT,
30 | IRenderView.AR_ASPECT_FILL_PARENT,
31 | IRenderView.AR_ASPECT_WRAP_CONTENT,
32 | IRenderView.AR_MATCH_PARENT,
33 | IRenderView.AR_16_9_FIT_PARENT,
34 | IRenderView.AR_4_3_FIT_PARENT};
35 |
36 | private Activity mActivity;
37 | private Uri mUri;
38 | private Map mHeaders;
39 | private IMediaPlayer mMediaPlayer = null;
40 |
41 | private IRenderView mRenderView;
42 | private int mVideoWidth = 0;
43 | private int mVideoHeight = 0;
44 | private int mVideoSarNum;
45 | private int mVideoSarDen;
46 | private int mSurfaceWidth;
47 | private int mSurfaceHeight;
48 | private int mVideoRotationDegree;
49 |
50 | //-------------------------
51 | // Extend: Aspect Ratio
52 | //-------------------------
53 | private int mCurrentAspectRatioIndex = 0;
54 | private int mCurrentAspectRatio = ALL_ASPECT_RATIO[0];
55 | private boolean mIsLive = false;// is Live mode
56 | private boolean mIsPause = false;
57 | private int mPausePosition;
58 | private IPlayerListener mPlayerListener;
59 | private boolean mIsPlayerSupport;
60 |
61 | private IRenderView.IRenderCallback mSHCallback = new IRenderView.IRenderCallback() {
62 | @Override
63 | public void onSurfaceChanged(@NonNull IRenderView.ISurfaceHolder holder, int format, int w, int h) {
64 | if (holder.getRenderView() != mRenderView) {
65 | ULog.e("onSurfaceChanged: unmatched render callback");
66 | return;
67 | }
68 | mSurfaceWidth = w;
69 | mSurfaceHeight = h;
70 | boolean isValidState = (getManager().mTargetState == MediaManager.STATE_PLAYING);
71 | boolean hasValidSize = !mRenderView.shouldWaitForResize() || (mVideoWidth == w && mVideoHeight == h);
72 | if (mMediaPlayer != null && isValidState && hasValidSize) {
73 | if (getManager().mSeekWhenPrepared != 0) {
74 | seekTo(getManager().mSeekWhenPrepared);
75 | }
76 | start();
77 | }
78 | }
79 |
80 | @Override
81 | public void onSurfaceCreated(@NonNull IRenderView.ISurfaceHolder holder, int width, int height) {
82 | if (holder.getRenderView() != mRenderView) {
83 | ULog.e("onSurfaceCreated: unmatched render callback");
84 | return;
85 | }
86 | if (mMediaPlayer != null) {
87 | bindSurfaceHolder(mMediaPlayer, holder);
88 | } else {
89 | prepare();
90 | }
91 | }
92 |
93 | @Override
94 | public void onSurfaceDestroyed(@NonNull IRenderView.ISurfaceHolder holder) {
95 | if (holder.getRenderView() != mRenderView) {
96 | ULog.e("onSurfaceDestroyed: unmatched render callback");
97 | return;
98 | }
99 | // after we return from this we can't use the surface any more
100 | if (mMediaPlayer != null) {
101 | mMediaPlayer.setDisplay(null);
102 | }
103 | }
104 | };
105 |
106 |
107 | public IjkVideoView(Context context) {
108 | super(context);
109 | init(context);
110 | }
111 |
112 | public IjkVideoView(Context context, AttributeSet attrs) {
113 | super(context, attrs);
114 | init(context);
115 | }
116 |
117 | public IjkVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
118 | super(context, attrs, defStyleAttr);
119 | init(context);
120 | }
121 |
122 | private void init(Context context) {
123 | this.mActivity = (Activity) context;
124 | // init player
125 | try {
126 | IjkMediaPlayer.loadLibrariesOnce(null);
127 | IjkMediaPlayer.native_profileBegin("libijkplayer.so");
128 | mIsPlayerSupport = true;
129 | } catch (Throwable e) {
130 | ULog.e("GiraffePlayer loadLibraries error" + e);
131 | }
132 |
133 | initBackground();
134 | setFocusable(true);
135 | setFocusableInTouchMode(true);
136 | requestFocus();
137 | }
138 |
139 | private void initBackground() {
140 | boolean enable = new Settings(mActivity.getApplicationContext()).getEnableBackgroundPlay();
141 | if (enable) {
142 | MediaPlayerService.intentToStart(getContext());
143 | MediaPlayerService.getMediaManager(mActivity);
144 | } else {
145 | getManager();
146 | }
147 | }
148 |
149 | private MediaManager getManager() {
150 | return MediaManager.instance(mActivity);
151 | }
152 |
153 | public IRenderView getRenderView() {
154 | return mRenderView;
155 | }
156 |
157 | private void addRenderView() {
158 | IRenderView renderView = Factory.initRenders(mActivity);
159 | if (this.mRenderView != null) {
160 | if (mMediaPlayer != null) {
161 | mMediaPlayer.setDisplay(null);
162 | }
163 | removeAllViews();
164 | this.mRenderView.removeRenderCallback(mSHCallback);
165 | this.mRenderView = null;
166 | }
167 | if (renderView == null) {
168 | return;
169 | }
170 |
171 | this.mRenderView = renderView;
172 | if (mVideoWidth > 0 && mVideoHeight > 0) {
173 | this.mRenderView.setVideoSize(mVideoWidth, mVideoHeight);
174 | }
175 | if (mVideoSarNum > 0 && mVideoSarDen > 0) {
176 | this.mRenderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
177 | }
178 | this.mRenderView.setAspectRatio(mCurrentAspectRatio);
179 | this.mRenderView.setVideoRotation(mVideoRotationDegree);
180 | this.mRenderView.addRenderCallback(mSHCallback);
181 | View view = this.mRenderView.getView();
182 | LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER);
183 | view.setLayoutParams(lp);
184 | addView(view);
185 | }
186 |
187 | /**
188 | * Sets video URI using specific headers.
189 | *
190 | * @param uri the URI of the video.
191 | * @param headers the headers for the URI request.
192 | * Note that the cross domain redirection is allowed by default, but that can be
193 | * changed with key/value pairs through the headers parameter with
194 | * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value
195 | * to disallow or allow cross domain redirection.
196 | */
197 | private void setVideoURI(Uri uri, Map headers) {
198 | this.mUri = uri;
199 | this.mHeaders = headers;
200 | prepare();
201 | }
202 |
203 | private void prepare() {
204 | if (mUri == null) {
205 | // not ready for playback just yet, will try again later
206 | return;
207 | }
208 | mMediaPlayer = getManager().prepare(mActivity.getApplicationContext(), mUri, mHeaders, false);
209 | getManager().setListener(this);
210 | addRenderView();
211 | }
212 |
213 | private void bindSurfaceHolder(IMediaPlayer mp, IRenderView.ISurfaceHolder holder) {
214 | if (mp == null) {
215 | return;
216 | }
217 | if (holder == null) {
218 | mp.setDisplay(null);
219 | return;
220 | }
221 | holder.bindToMediaPlayer(mp);
222 | }
223 |
224 | /**
225 | * release the media player in any state
226 | */
227 | public void release(boolean clearTargetState) {
228 | getManager().release(mActivity.getApplicationContext(), clearTargetState);
229 | mMediaPlayer = null;
230 | }
231 |
232 | @Override
233 | public void start() {
234 | getManager().start();
235 | }
236 |
237 | @Override
238 | public void pause() {
239 | getManager().pause();
240 | }
241 |
242 | @Override
243 | public int getDuration() {
244 | return getManager().getDuration();
245 | }
246 |
247 | @Override
248 | public int getCurrentPosition() {
249 | return getManager().getCurrentPosition();
250 | }
251 |
252 | @Override
253 | public void seekTo(int msec) {
254 | getManager().seekTo(msec);
255 | }
256 |
257 | @Override
258 | public boolean isPlaying() {
259 | return getManager().isPlaying();
260 | }
261 |
262 | @Override
263 | public int getBufferPercentage() {
264 | return getManager().getBufferPercentage();
265 | }
266 |
267 | @Override
268 | public boolean canPause() {
269 | return false;
270 | }
271 |
272 | @Override
273 | public boolean canSeekBackward() {
274 | return false;
275 | }
276 |
277 | @Override
278 | public boolean canSeekForward() {
279 | return false;
280 | }
281 |
282 | @Override
283 | public int getAudioSessionId() {
284 | return 0;
285 | }
286 |
287 | @Override
288 | public void onLoading() {
289 | if (mActivity == null || mActivity.isFinishing()) {
290 | return;
291 | }
292 | if (mPlayerListener != null) {
293 | mPlayerListener.onLoading();
294 | }
295 | }
296 |
297 | @Override
298 | public void onCompletion(IMediaPlayer mp) {
299 | if (mActivity == null || mActivity.isFinishing()) {
300 | return;
301 | }
302 | if (mPlayerListener != null) {
303 | mPlayerListener.onCompletion(mp);
304 | }
305 | }
306 |
307 | @Override
308 | public void onPrepared(IMediaPlayer mp) {
309 | if (mActivity == null || mActivity.isFinishing()) {
310 | return;
311 | }
312 | setArgs(mp);
313 | if (mVideoWidth != 0 && mVideoHeight != 0) {
314 | if (mRenderView != null) {
315 | mRenderView.setVideoSize(mVideoWidth, mVideoHeight);
316 | mRenderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
317 | if (!mRenderView.shouldWaitForResize() || mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) {
318 | // We didn't actually change the size (it was already at the size
319 | // we need), so we won't get a "surface changed" callback, so
320 | // start the video here instead of in the callback.
321 | if (getManager().mTargetState == MediaManager.STATE_PLAYING) {
322 | start();
323 | } else if (!isPlaying() && (getManager().mSeekWhenPrepared != 0
324 | || getCurrentPosition() > 0)) {
325 | // Show the media controls when we're paused into a video and make 'em stick.
326 | }
327 | }
328 | }
329 | } else {
330 | // We don't know the video size yet, but should start anyway.
331 | // The video size might be reported to us later.
332 | if (getManager().mTargetState == MediaManager.STATE_PLAYING) {
333 | start();
334 | }
335 | }
336 |
337 | if (mPlayerListener != null) {
338 | mPlayerListener.onPrepared(mp);
339 | }
340 | }
341 |
342 | @Override
343 | public boolean onError(IMediaPlayer mp, int what, int extra) {
344 | if (mActivity == null || mActivity.isFinishing()) {
345 | return false;
346 | }
347 | return mPlayerListener != null && mPlayerListener.onError(mp, what, extra);
348 | }
349 |
350 | @Override
351 | public boolean onInfo(IMediaPlayer mp, int what, int extra) {
352 | // 当what为MEDIA_INFO_VIDEO_RENDERING_START时播放第一帧画面了
353 | if (mActivity == null || mActivity.isFinishing()) {
354 | return false;
355 | }
356 | switch (what) {
357 | case IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED:
358 | mVideoRotationDegree = extra;
359 | ULog.d("MEDIA_INFO_VIDEO_ROTATION_CHANGED: " + extra);
360 | if (mRenderView != null) {
361 | mRenderView.setVideoRotation(extra);
362 | }
363 | break;
364 | // case IMediaPlayer.MEDIA_INFO_...
365 | }
366 | return mPlayerListener == null || mPlayerListener.onInfo(mp, what, extra);
367 | }
368 |
369 | @Override
370 | public void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sarNum, int sarDen) {
371 | if (mActivity == null || mActivity.isFinishing()) {
372 | return;
373 | }
374 | setArgs(mp);
375 | if (mVideoWidth != 0 && mVideoHeight != 0) {
376 | if (mRenderView != null) {
377 | mRenderView.setVideoSize(mVideoWidth, mVideoHeight);
378 | mRenderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
379 | }
380 | requestLayout();
381 | }
382 | if (mPlayerListener != null) {
383 | mPlayerListener.onVideoSizeChanged(mp, width, height, sarNum, sarDen);
384 | }
385 | }
386 |
387 | private void setArgs(IMediaPlayer mp) {
388 | mVideoWidth = mp.getVideoWidth();
389 | mVideoHeight = mp.getVideoHeight();
390 | mVideoSarNum = mp.getVideoSarNum();
391 | mVideoSarDen = mp.getVideoSarDen();
392 | }
393 |
394 | public void setLive(boolean live) {
395 | mIsLive = live;
396 | }
397 |
398 | /**
399 | * Sets video path.
400 | *
401 | * @param path the path of the video.
402 | */
403 | public void setVideoPath(String path) {
404 | setVideoURI(Uri.parse(path));
405 | }
406 |
407 | /**
408 | * Sets video URI.
409 | *
410 | * @param uri the URI of the video.
411 | */
412 | public void setVideoURI(Uri uri) {
413 | setVideoURI(uri, null);
414 | }
415 |
416 | public void play(String url, int pos) {
417 | setVideoPath(url);
418 | seekTo(pos);
419 | start();
420 | onLoading();
421 | }
422 |
423 | public void onResume() {
424 | if (mIsPause) {
425 | mIsPause = false;
426 | prepare();
427 | seekTo(mIsLive ? 0 : mPausePosition);
428 | start();
429 | onLoading();
430 | }
431 | }
432 |
433 | public void onPause() {
434 | mIsPause = true;
435 | if (mIsLive) {
436 | release(false);
437 | } else {
438 | mPausePosition = getCurrentPosition();
439 | getManager().pause();
440 | }
441 | }
442 |
443 | public void onDestroy() {
444 | release(true);
445 | }
446 |
447 | public void setScaleType(int scaleType) {
448 | if (mRenderView != null) {
449 | for (int index : ALL_ASPECT_RATIO) {
450 | if (index == scaleType) {
451 | mCurrentAspectRatioIndex = index;
452 | }
453 | }
454 | mRenderView.setAspectRatio(scaleType);
455 | }
456 | }
457 |
458 | public int toggleAspectRatio() {
459 | mCurrentAspectRatioIndex++;
460 | mCurrentAspectRatioIndex %= ALL_ASPECT_RATIO.length;
461 | mCurrentAspectRatio = ALL_ASPECT_RATIO[mCurrentAspectRatioIndex];
462 | if (mRenderView != null) {
463 | mRenderView.setAspectRatio(mCurrentAspectRatio);
464 | }
465 | return mCurrentAspectRatio;
466 | }
467 |
468 | public void setOnPlayerListener(IPlayerListener iPlayerListener) {
469 | mPlayerListener = iPlayerListener;
470 | }
471 | }
472 |
--------------------------------------------------------------------------------