├── app
├── .gitignore
├── libs
│ ├── x86
│ │ ├── libijksdl.so
│ │ ├── libijkffmpeg.so
│ │ └── libijkplayer.so
│ ├── armeabi
│ │ ├── libijksdl.so
│ │ ├── libijkffmpeg.so
│ │ └── libijkplayer.so
│ ├── x86_64
│ │ ├── libijksdl.so
│ │ ├── libijkffmpeg.so
│ │ └── libijkplayer.so
│ ├── arm64-v8a
│ │ ├── libijksdl.so
│ │ ├── libijkffmpeg.so
│ │ └── libijkplayer.so
│ ├── armeabi-v7a
│ │ ├── libijksdl.so
│ │ ├── libijkffmpeg.so
│ │ └── libijkplayer.so
│ └── ijkplayer-java-release.aar
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── styles.xml
│ │ │ ├── drawable
│ │ │ │ ├── loading.png
│ │ │ │ ├── bar_light.png
│ │ │ │ ├── bar_sound.png
│ │ │ │ ├── btn_back.png
│ │ │ │ ├── btn_full.png
│ │ │ │ ├── btn_mini.png
│ │ │ │ ├── btn_pause.png
│ │ │ │ ├── btn_play.png
│ │ │ │ ├── seekbar_ratio.png
│ │ │ │ ├── btn_back_active.png
│ │ │ │ ├── btn_full_active.png
│ │ │ │ ├── btn_pause_active.png
│ │ │ │ ├── btn_play_active.png
│ │ │ │ ├── play_btn_back.xml
│ │ │ │ ├── play_btn_full.xml
│ │ │ │ ├── play_btn_play.xml
│ │ │ │ ├── play_btn_pause.xml
│ │ │ │ ├── shar_list_item.xml
│ │ │ │ ├── shape_top.xml
│ │ │ │ ├── shape_bottom.xml
│ │ │ │ ├── thumb_image.xml
│ │ │ │ ├── shar_list.xml
│ │ │ │ ├── po_seekbar.xml
│ │ │ │ └── progress_vertical.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── values-w820dp
│ │ │ │ └── dimens.xml
│ │ │ └── layout
│ │ │ │ ├── shar_list_text_item.xml
│ │ │ │ ├── activity_main.xml
│ │ │ │ └── play.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── codef
│ │ │ │ └── ijkplay_demo
│ │ │ │ ├── ijkplayer
│ │ │ │ ├── IVideoEvent.java
│ │ │ │ ├── IMediaController.java
│ │ │ │ ├── FileMediaDataSource.java
│ │ │ │ ├── IRenderView.java
│ │ │ │ ├── MediaPlayerCompat.java
│ │ │ │ ├── SurfaceRenderView.java
│ │ │ │ ├── MeasureHelper.java
│ │ │ │ ├── TextureRenderView.java
│ │ │ │ ├── IjkVideoView.java
│ │ │ │ └── ijkvideo.java
│ │ │ │ └── MainActivity.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── codef
│ │ │ └── ijkplay_demo
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── codef
│ │ └── ijkplay_demo
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── image
├── 1.png
├── 2.png
└── 3.png
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── README.md
├── gradle.properties
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/image/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/image/1.png
--------------------------------------------------------------------------------
/image/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/image/2.png
--------------------------------------------------------------------------------
/image/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/image/3.png
--------------------------------------------------------------------------------
/app/libs/x86/libijksdl.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/libs/x86/libijksdl.so
--------------------------------------------------------------------------------
/app/libs/armeabi/libijksdl.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/libs/armeabi/libijksdl.so
--------------------------------------------------------------------------------
/app/libs/x86/libijkffmpeg.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/libs/x86/libijkffmpeg.so
--------------------------------------------------------------------------------
/app/libs/x86/libijkplayer.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/libs/x86/libijkplayer.so
--------------------------------------------------------------------------------
/app/libs/x86_64/libijksdl.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/libs/x86_64/libijksdl.so
--------------------------------------------------------------------------------
/app/libs/arm64-v8a/libijksdl.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/libs/arm64-v8a/libijksdl.so
--------------------------------------------------------------------------------
/app/libs/armeabi/libijkffmpeg.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/libs/armeabi/libijkffmpeg.so
--------------------------------------------------------------------------------
/app/libs/armeabi/libijkplayer.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/libs/armeabi/libijkplayer.so
--------------------------------------------------------------------------------
/app/libs/x86_64/libijkffmpeg.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/libs/x86_64/libijkffmpeg.so
--------------------------------------------------------------------------------
/app/libs/x86_64/libijkplayer.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/libs/x86_64/libijkplayer.so
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ijkplay_demo
3 |
4 |
--------------------------------------------------------------------------------
/app/libs/arm64-v8a/libijkffmpeg.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/libs/arm64-v8a/libijkffmpeg.so
--------------------------------------------------------------------------------
/app/libs/arm64-v8a/libijkplayer.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/libs/arm64-v8a/libijkplayer.so
--------------------------------------------------------------------------------
/app/libs/armeabi-v7a/libijksdl.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/libs/armeabi-v7a/libijksdl.so
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/libs/armeabi-v7a/libijkffmpeg.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/libs/armeabi-v7a/libijkffmpeg.so
--------------------------------------------------------------------------------
/app/libs/armeabi-v7a/libijkplayer.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/libs/armeabi-v7a/libijkplayer.so
--------------------------------------------------------------------------------
/app/libs/ijkplayer-java-release.aar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/libs/ijkplayer-java-release.aar
--------------------------------------------------------------------------------
/app/src/main/res/drawable/loading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/src/main/res/drawable/loading.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bar_light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/src/main/res/drawable/bar_light.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bar_sound.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/src/main/res/drawable/bar_sound.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/src/main/res/drawable/btn_back.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_full.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/src/main/res/drawable/btn_full.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_mini.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/src/main/res/drawable/btn_mini.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/src/main/res/drawable/btn_pause.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/src/main/res/drawable/btn_play.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/seekbar_ratio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/src/main/res/drawable/seekbar_ratio.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_back_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/src/main/res/drawable/btn_back_active.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_full_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/src/main/res/drawable/btn_full_active.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_pause_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/src/main/res/drawable/btn_pause_active.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/btn_play_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/src/main/res/drawable/btn_play_active.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodFrm/ijkplayer_demo/master/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 | .idea
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Oct 06 10:53:57 CST 2018
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.6-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 | #1496db
7 |
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ijkplayer 播放器demo
2 |
3 | > 支持左右滑动快进,左右上下滑动调音量
4 |
5 | > 感觉还有不少BUG,慢慢完善
6 |
7 | ## ijkplayer 项目地址
8 | [https://github.com/Bilibili/ijkplayer](https://github.com/Bilibili/ijkplayer)
9 |
10 | ## Demo截图
11 |
12 | 
13 | 
14 | 
15 |
16 | > **我用的是b站开源的播放器写的,凭什么说我抄袭**
17 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/play_btn_back.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/play_btn_full.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/play_btn_play.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/play_btn_pause.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/codef/ijkplay_demo/ijkplayer/IVideoEvent.java:
--------------------------------------------------------------------------------
1 | package com.example.codef.ijkplay_demo.ijkplayer;
2 |
3 | /**
4 | * Created by codef on 2018/2/7.
5 | */
6 |
7 | public interface IVideoEvent {
8 | void onFullScreen();
9 |
10 | boolean onError(int i);
11 |
12 | void onReception();
13 |
14 | void onBackstage();
15 |
16 | boolean onSharSwitch(String Name, String Url);
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shar_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
6 |
7 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_top.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/shar_list_text_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/thumb_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shar_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/test/java/com/example/codef/ijkplay_demo/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.example.codef.ijkplay_demo;
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() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/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 C:\Users\codef\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/po_seekbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 | -
9 |
10 |
11 |
12 |
13 |
14 |
15 | -
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | ## Project-wide Gradle settings.
2 | #
3 | # For more details on how to configure your build environment visit
4 | # http://www.gradle.org/docs/current/userguide/build_environment.html
5 | #
6 | # Specifies the JVM arguments used for the daemon process.
7 | # The setting is particularly useful for tweaking memory settings.
8 | # Default value: -Xmx1024m -XX:MaxPermSize=256m
9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
10 | #
11 | # When configured, Gradle will run in incubating parallel mode.
12 | # This option should only be used with decoupled projects. More details, visit
13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
14 | # org.gradle.parallel=true
15 | #Fri Aug 18 16:25:15 CST 2017
16 | systemProp.http.proxyHost=127.0.0.1
17 | org.gradle.jvmargs=-Xmx1536m
18 | systemProp.http.proxyPort=1081
19 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/example/codef/ijkplay_demo/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.example.codef.ijkplay_demo;
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() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.example.codef.ijkplay_demo", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/progress_vertical.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
12 |
13 |
14 |
15 | -
16 |
18 |
19 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
18 |
19 |
27 |
28 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 26
5 | buildToolsVersion '27.0.3'
6 | defaultConfig {
7 | applicationId "com.example.codef.ijkplay_demo"
8 | minSdkVersion 15
9 | targetSdkVersion 26
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | sourceSets {
21 | main {
22 | jniLibs.srcDirs = ['libs']
23 | }
24 | }
25 | }
26 |
27 | repositories {
28 | mavenCentral()
29 | flatDir {
30 | dirs 'libs' //this way we can find the .aar file in libs folder
31 | }
32 | }
33 | dependencies {
34 | compile fileTree(include: ['*.jar'], dir: 'libs')
35 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
36 | exclude group: 'com.android.support', module: 'support-annotations'
37 | })
38 | compile 'com.android.support:appcompat-v7:26.0.0-alpha1'
39 | testCompile 'junit:junit:4.12'
40 | compile(name: 'ijkplayer-java-release', ext: 'aar')
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/codef/ijkplay_demo/ijkplayer/IMediaController.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Zhang Rui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.example.codef.ijkplay_demo.ijkplayer;
18 |
19 | import android.view.View;
20 | import android.widget.MediaController;
21 |
22 | public interface IMediaController {
23 | void hide();
24 |
25 | boolean isShowing();
26 |
27 | void setAnchorView(View view);
28 |
29 | void setEnabled(boolean enabled);
30 |
31 | void setMediaPlayer(MediaController.MediaPlayerControl player);
32 |
33 | void show(int timeout);
34 |
35 | void show();
36 |
37 | //----------
38 | // Extends
39 | //----------
40 | void showOnce(View view);
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/codef/ijkplay_demo/ijkplayer/FileMediaDataSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Zhang Rui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.example.codef.ijkplay_demo.ijkplayer;
18 |
19 | import java.io.File;
20 | import java.io.IOException;
21 | import java.io.RandomAccessFile;
22 |
23 | import tv.danmaku.ijk.media.player.misc.IMediaDataSource;
24 |
25 | public class FileMediaDataSource implements IMediaDataSource {
26 | private RandomAccessFile mFile;
27 | private long mFileSize;
28 |
29 | public FileMediaDataSource(File file) throws IOException {
30 | mFile = new RandomAccessFile(file, "r");
31 | mFileSize = mFile.length();
32 | }
33 |
34 | @Override
35 | public int readAt(long position, byte[] buffer, int offset, int size) throws IOException {
36 | if (mFile.getFilePointer() != position)
37 | mFile.seek(position);
38 |
39 | if (size == 0)
40 | return 0;
41 |
42 | return mFile.read(buffer, 0, size);
43 | }
44 |
45 | @Override
46 | public long getSize() throws IOException {
47 | return mFileSize;
48 | }
49 |
50 | @Override
51 | public void close() throws IOException {
52 | mFileSize = 0;
53 | mFile.close();
54 | mFile = null;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/codef/ijkplay_demo/ijkplayer/IRenderView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Zhang Rui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.example.codef.ijkplay_demo.ijkplayer;
18 |
19 | import android.graphics.SurfaceTexture;
20 | import android.support.annotation.NonNull;
21 | import android.support.annotation.Nullable;
22 | import android.view.Surface;
23 | import android.view.SurfaceHolder;
24 | import android.view.View;
25 |
26 | import tv.danmaku.ijk.media.player.IMediaPlayer;
27 |
28 | public interface IRenderView {
29 | int AR_ASPECT_FIT_PARENT = 0; // without clip
30 | int AR_ASPECT_FILL_PARENT = 1; // may clip
31 | int AR_ASPECT_WRAP_CONTENT = 2;
32 | int AR_MATCH_PARENT = 3;
33 | int AR_16_9_FIT_PARENT = 4;
34 | int AR_4_3_FIT_PARENT = 5;
35 |
36 | View getView();
37 |
38 | boolean shouldWaitForResize();
39 |
40 | void setVideoSize(int videoWidth, int videoHeight);
41 |
42 | void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen);
43 |
44 | void setVideoRotation(int degree);
45 |
46 | void setAspectRatio(int aspectRatio);
47 |
48 | void addRenderCallback(@NonNull IRenderCallback callback);
49 |
50 | void removeRenderCallback(@NonNull IRenderCallback callback);
51 |
52 | interface ISurfaceHolder {
53 | void bindToMediaPlayer(IMediaPlayer mp);
54 |
55 | @NonNull
56 | IRenderView getRenderView();
57 |
58 | @Nullable
59 | SurfaceHolder getSurfaceHolder();
60 |
61 | @Nullable
62 | Surface openSurface();
63 |
64 | @Nullable
65 | SurfaceTexture getSurfaceTexture();
66 | }
67 |
68 | interface IRenderCallback {
69 | /**
70 | * @param holder
71 | * @param width could be 0
72 | * @param height could be 0
73 | */
74 | void onSurfaceCreated(@NonNull ISurfaceHolder holder, int width, int height);
75 |
76 | /**
77 | * @param holder
78 | * @param format could be 0
79 | * @param width
80 | * @param height
81 | */
82 | void onSurfaceChanged(@NonNull ISurfaceHolder holder, int format, int width, int height);
83 |
84 | void onSurfaceDestroyed(@NonNull ISurfaceHolder holder);
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/codef/ijkplay_demo/ijkplayer/MediaPlayerCompat.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Zhang Rui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.example.codef.ijkplay_demo.ijkplayer;
18 |
19 | import tv.danmaku.ijk.media.player.IMediaPlayer;
20 | import tv.danmaku.ijk.media.player.IjkMediaPlayer;
21 | import tv.danmaku.ijk.media.player.MediaPlayerProxy;
22 | import tv.danmaku.ijk.media.player.TextureMediaPlayer;
23 |
24 | public class MediaPlayerCompat {
25 | public static String getName(IMediaPlayer mp) {
26 | if (mp == null) {
27 | return "null";
28 | } else if (mp instanceof TextureMediaPlayer) {
29 | StringBuilder sb = new StringBuilder("TextureMediaPlayer <");
30 | IMediaPlayer internalMediaPlayer = ((TextureMediaPlayer) mp).getInternalMediaPlayer();
31 | if (internalMediaPlayer == null) {
32 | sb.append("null>");
33 | } else {
34 | sb.append(internalMediaPlayer.getClass().getSimpleName());
35 | sb.append(">");
36 | }
37 | return sb.toString();
38 | } else {
39 | return mp.getClass().getSimpleName();
40 | }
41 | }
42 |
43 | public static IjkMediaPlayer getIjkMediaPlayer(IMediaPlayer mp) {
44 | IjkMediaPlayer ijkMediaPlayer = null;
45 | if (mp == null) {
46 | return null;
47 | } if (mp instanceof IjkMediaPlayer) {
48 | ijkMediaPlayer = (IjkMediaPlayer) mp;
49 | } else if (mp instanceof MediaPlayerProxy && ((MediaPlayerProxy) mp).getInternalMediaPlayer() instanceof IjkMediaPlayer) {
50 | ijkMediaPlayer = (IjkMediaPlayer) ((MediaPlayerProxy) mp).getInternalMediaPlayer();
51 | }
52 | return ijkMediaPlayer;
53 | }
54 |
55 | public static void selectTrack(IMediaPlayer mp, int stream) {
56 | IjkMediaPlayer ijkMediaPlayer = getIjkMediaPlayer(mp);
57 | if (ijkMediaPlayer == null)
58 | return;
59 | ijkMediaPlayer.selectTrack(stream);
60 | }
61 |
62 | public static void deselectTrack(IMediaPlayer mp, int stream) {
63 | IjkMediaPlayer ijkMediaPlayer = getIjkMediaPlayer(mp);
64 | if (ijkMediaPlayer == null)
65 | return;
66 | ijkMediaPlayer.deselectTrack(stream);
67 | }
68 |
69 | public static int getSelectedTrack(IMediaPlayer mp, int trackType) {
70 | IjkMediaPlayer ijkMediaPlayer = getIjkMediaPlayer(mp);
71 | if (ijkMediaPlayer == null)
72 | return -1;
73 | return ijkMediaPlayer.getSelectedTrack(trackType);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/codef/ijkplay_demo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.codef.ijkplay_demo;
2 |
3 | import android.os.Bundle;
4 | import android.os.Handler;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.util.Log;
7 | import android.view.View;
8 | import android.widget.TextView;
9 |
10 | import com.example.codef.ijkplay_demo.ijkplayer.IVideoEvent;
11 | import com.example.codef.ijkplay_demo.ijkplayer.ijkvideo;
12 |
13 | import java.io.File;
14 | import java.io.FileOutputStream;
15 | import java.util.regex.Matcher;
16 | import java.util.regex.Pattern;
17 |
18 | public class MainActivity extends AppCompatActivity implements IVideoEvent {
19 | ijkvideo ijk;
20 |
21 | @Override
22 | protected void onCreate(Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 | setContentView(R.layout.activity_main);
25 | if (getSupportActionBar() != null) {
26 | getSupportActionBar().hide();
27 | }
28 | initPlayer();
29 | }
30 |
31 | public void initPlayer() {
32 | ijk = new ijkvideo(this);
33 | ijk.setEvent(this);
34 | ijk.createPlayer(0, 0, 1080, 640);
35 | String url = "https://ltsbsy.qq.com/uwMRJfz-r5jAYaQXGdGnC2_ppdhgmrDlPaRvaV7F2Ic/yh_2B1nhzSQO8pmHVDtC_heqD2D06Rz5orVR78ZbYmE8RDaw66GCnh-s_uM3MT0rDXMgm-lc2iBQVB2tO4q5pf4igyQpobr1KYPLRY5i1iYL5N6dWJE6JfrubGKHAnE9dg8cZ3XcE3VfpH2z93vIhLbLiqxidzUQ/y0016tj0qvh.321002.ts.m3u8?ver=4";
36 | ijk.toggleAspectRatio(3);
37 | // ijk.addHeader("test","header");
38 | // ijk.addHeader("emmm","qwerqwe");
39 | // ijk.addShar("test","emm");
40 | //ijk.selectShar("呵呵");
41 | // ijk.clearHeader();
42 | ijk.setVideoUrl(url);
43 |
44 | ijk.start();
45 | }
46 |
47 | @Override
48 | public void onReception() {
49 | ijk.start();
50 | }
51 |
52 | @Override
53 | public boolean onSharSwitch(String Name, String Url) {
54 | return false;
55 | }
56 |
57 | @Override
58 | public void onBackstage() {
59 | ijk.pause();
60 | }
61 |
62 |
63 | public void btnClick(View v) {
64 | new Handler().post(new Runnable() {
65 | @Override
66 | public void run() {
67 | ijk.setTitle("我是标题标题我是标题标题我是标题标题我是标题标题我是标题标题我是标题标题我是标题标题我是标题标题我是标题标题我是标题标题我是标题标题");
68 | ijk.addShar("测试", "http://mvvideo10.meitudata.com/5a73fac39cd785585_H264_15.mp4?k=70bc472f07e2e87e16a91f102bedfdfc&t=5a841e82");
69 | ijk.addShar("呵呵", "http://192.168.1.10/v.f4v");
70 | ijk.addShar("会更好的", "http://182.61.16.216:1086/app/cache/m3u8/b747824b910f2e7c48d84555db972000.xml");
71 | ijk.selectShar("会更好的");
72 | }
73 |
74 | });
75 | // ijk.fullScreen();
76 | }
77 |
78 | @Override
79 | public void onFullScreen() {
80 | int a = 0;
81 | a = a + 2;
82 | Log.e(null, "error");
83 | }
84 |
85 | @Override
86 | public boolean onError(int i) {
87 | ((TextView) findViewById(R.id.text_error)).setText(i);
88 | Log.e(null, "error:code:" + i);
89 | return false;
90 | }
91 |
92 | @Override
93 | public void onDestroy() {
94 | ijk.deletePlayer();
95 | super.onDestroy();
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/codef/ijkplay_demo/ijkplayer/SurfaceRenderView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Zhang Rui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.example.codef.ijkplay_demo.ijkplayer;
18 |
19 | import android.annotation.TargetApi;
20 | import android.content.Context;
21 | import android.graphics.SurfaceTexture;
22 | import android.os.Build;
23 | import android.support.annotation.NonNull;
24 | import android.support.annotation.Nullable;
25 | import android.util.AttributeSet;
26 | import android.util.Log;
27 | import android.view.Surface;
28 | import android.view.SurfaceHolder;
29 | import android.view.SurfaceView;
30 | import android.view.View;
31 | import android.view.accessibility.AccessibilityEvent;
32 | import android.view.accessibility.AccessibilityNodeInfo;
33 |
34 | import java.lang.ref.WeakReference;
35 | import java.util.Map;
36 | import java.util.concurrent.ConcurrentHashMap;
37 |
38 | import tv.danmaku.ijk.media.player.IMediaPlayer;
39 | import tv.danmaku.ijk.media.player.ISurfaceTextureHolder;
40 |
41 | public class SurfaceRenderView extends SurfaceView implements IRenderView {
42 | private MeasureHelper mMeasureHelper;
43 |
44 | public SurfaceRenderView(Context context) {
45 | super(context);
46 | initView(context);
47 | }
48 |
49 | public SurfaceRenderView(Context context, AttributeSet attrs) {
50 | super(context, attrs);
51 | initView(context);
52 | }
53 |
54 | public SurfaceRenderView(Context context, AttributeSet attrs, int defStyleAttr) {
55 | super(context, attrs, defStyleAttr);
56 | initView(context);
57 | }
58 |
59 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
60 | public SurfaceRenderView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
61 | super(context, attrs, defStyleAttr, defStyleRes);
62 | initView(context);
63 | }
64 |
65 | private void initView(Context context) {
66 | mMeasureHelper = new MeasureHelper(this);
67 | mSurfaceCallback = new SurfaceCallback(this);
68 | getHolder().addCallback(mSurfaceCallback);
69 | //noinspection deprecation
70 | getHolder().setType(SurfaceHolder.SURFACE_TYPE_NORMAL);
71 | }
72 |
73 | @Override
74 | public View getView() {
75 | return this;
76 | }
77 |
78 | @Override
79 | public boolean shouldWaitForResize() {
80 | return true;
81 | }
82 |
83 | //--------------------
84 | // Layout & Measure
85 | //--------------------
86 | @Override
87 | public void setVideoSize(int videoWidth, int videoHeight) {
88 | if (videoWidth > 0 && videoHeight > 0) {
89 | mMeasureHelper.setVideoSize(videoWidth, videoHeight);
90 | getHolder().setFixedSize(videoWidth, videoHeight);
91 | requestLayout();
92 | }
93 | }
94 |
95 | @Override
96 | public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) {
97 | if (videoSarNum > 0 && videoSarDen > 0) {
98 | mMeasureHelper.setVideoSampleAspectRatio(videoSarNum, videoSarDen);
99 | requestLayout();
100 | }
101 | }
102 |
103 | @Override
104 | public void setVideoRotation(int degree) {
105 | Log.e("", "SurfaceView doesn't support rotation (" + degree + ")!\n");
106 | }
107 |
108 | @Override
109 | public void setAspectRatio(int aspectRatio) {
110 | mMeasureHelper.setAspectRatio(aspectRatio);
111 | requestLayout();
112 | }
113 |
114 | @Override
115 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
116 | mMeasureHelper.doMeasure(widthMeasureSpec, heightMeasureSpec);
117 | setMeasuredDimension(mMeasureHelper.getMeasuredWidth(), mMeasureHelper.getMeasuredHeight());
118 | }
119 |
120 | //--------------------
121 | // SurfaceViewHolder
122 | //--------------------
123 |
124 | private static final class InternalSurfaceHolder implements IRenderView.ISurfaceHolder {
125 | private SurfaceRenderView mSurfaceView;
126 | private SurfaceHolder mSurfaceHolder;
127 |
128 | public InternalSurfaceHolder(@NonNull SurfaceRenderView surfaceView,
129 | @Nullable SurfaceHolder surfaceHolder) {
130 | mSurfaceView = surfaceView;
131 | mSurfaceHolder = surfaceHolder;
132 | }
133 |
134 | public void bindToMediaPlayer(IMediaPlayer mp) {
135 | if (mp != null) {
136 | if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) &&
137 | (mp instanceof ISurfaceTextureHolder)) {
138 | ISurfaceTextureHolder textureHolder = (ISurfaceTextureHolder) mp;
139 | textureHolder.setSurfaceTexture(null);
140 | }
141 | mp.setDisplay(mSurfaceHolder);
142 | }
143 | }
144 |
145 | @NonNull
146 | @Override
147 | public IRenderView getRenderView() {
148 | return mSurfaceView;
149 | }
150 |
151 | @Nullable
152 | @Override
153 | public SurfaceHolder getSurfaceHolder() {
154 | return mSurfaceHolder;
155 | }
156 |
157 | @Nullable
158 | @Override
159 | public SurfaceTexture getSurfaceTexture() {
160 | return null;
161 | }
162 |
163 | @Nullable
164 | @Override
165 | public Surface openSurface() {
166 | if (mSurfaceHolder == null)
167 | return null;
168 | return mSurfaceHolder.getSurface();
169 | }
170 | }
171 |
172 | //-------------------------
173 | // SurfaceHolder.Callback
174 | //-------------------------
175 |
176 | @Override
177 | public void addRenderCallback(IRenderCallback callback) {
178 | mSurfaceCallback.addRenderCallback(callback);
179 | }
180 |
181 | @Override
182 | public void removeRenderCallback(IRenderCallback callback) {
183 | mSurfaceCallback.removeRenderCallback(callback);
184 | }
185 |
186 | private SurfaceCallback mSurfaceCallback;
187 |
188 | private static final class SurfaceCallback implements SurfaceHolder.Callback {
189 | private SurfaceHolder mSurfaceHolder;
190 | private boolean mIsFormatChanged;
191 | private int mFormat;
192 | private int mWidth;
193 | private int mHeight;
194 |
195 | private WeakReference mWeakSurfaceView;
196 | private Map mRenderCallbackMap = new ConcurrentHashMap();
197 |
198 | public SurfaceCallback(@NonNull SurfaceRenderView surfaceView) {
199 | mWeakSurfaceView = new WeakReference(surfaceView);
200 | }
201 |
202 | public void addRenderCallback(@NonNull IRenderCallback callback) {
203 | mRenderCallbackMap.put(callback, callback);
204 |
205 | ISurfaceHolder surfaceHolder = null;
206 | if (mSurfaceHolder != null) {
207 | if (surfaceHolder == null)
208 | surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);
209 | callback.onSurfaceCreated(surfaceHolder, mWidth, mHeight);
210 | }
211 |
212 | if (mIsFormatChanged) {
213 | if (surfaceHolder == null)
214 | surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);
215 | callback.onSurfaceChanged(surfaceHolder, mFormat, mWidth, mHeight);
216 | }
217 | }
218 |
219 | public void removeRenderCallback(@NonNull IRenderCallback callback) {
220 | mRenderCallbackMap.remove(callback);
221 | }
222 |
223 | @Override
224 | public void surfaceCreated(SurfaceHolder holder) {
225 | mSurfaceHolder = holder;
226 | mIsFormatChanged = false;
227 | mFormat = 0;
228 | mWidth = 0;
229 | mHeight = 0;
230 |
231 | ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);
232 | for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
233 | renderCallback.onSurfaceCreated(surfaceHolder, 0, 0);
234 | }
235 | }
236 |
237 | @Override
238 | public void surfaceDestroyed(SurfaceHolder holder) {
239 | mSurfaceHolder = null;
240 | mIsFormatChanged = false;
241 | mFormat = 0;
242 | mWidth = 0;
243 | mHeight = 0;
244 |
245 | ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);
246 | for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
247 | renderCallback.onSurfaceDestroyed(surfaceHolder);
248 | }
249 | }
250 |
251 | @Override
252 | public void surfaceChanged(SurfaceHolder holder, int format,
253 | int width, int height) {
254 | mSurfaceHolder = holder;
255 | mIsFormatChanged = true;
256 | mFormat = format;
257 | mWidth = width;
258 | mHeight = height;
259 |
260 | // mMeasureHelper.setVideoSize(width, height);
261 |
262 | ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);
263 | for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
264 | renderCallback.onSurfaceChanged(surfaceHolder, format, width, height);
265 | }
266 | }
267 | }
268 |
269 | //--------------------
270 | // Accessibility
271 | //--------------------
272 |
273 | @Override
274 | public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
275 | super.onInitializeAccessibilityEvent(event);
276 | event.setClassName(SurfaceRenderView.class.getName());
277 | }
278 |
279 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
280 | @Override
281 | public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
282 | super.onInitializeAccessibilityNodeInfo(info);
283 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
284 | info.setClassName(SurfaceRenderView.class.getName());
285 | }
286 | }
287 | }
288 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/play.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
15 |
16 |
17 |
18 |
24 |
25 |
29 |
30 |
36 |
37 |
38 |
42 |
43 |
54 |
55 |
56 |
57 |
58 |
64 |
65 |
71 |
72 |
79 |
80 |
81 |
87 |
88 |
94 |
95 |
103 |
104 |
114 |
115 |
123 |
124 |
125 |
126 |
127 |
134 |
135 |
142 |
143 |
153 |
154 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
175 |
176 |
180 |
181 |
187 |
188 |
189 |
194 |
195 |
205 |
206 |
220 |
221 |
231 |
232 |
236 |
244 |
245 |
246 |
247 |
248 |
252 |
258 |
259 |
260 |
261 |
268 |
269 |
275 |
276 |
277 |
278 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/codef/ijkplay_demo/ijkplayer/MeasureHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Zhang Rui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.example.codef.ijkplay_demo.ijkplayer;
18 |
19 | import android.content.Context;
20 | import android.support.annotation.NonNull;
21 | import android.view.View;
22 |
23 | import java.lang.ref.WeakReference;
24 |
25 | public final class MeasureHelper {
26 | private WeakReference mWeakView;
27 |
28 | private int mVideoWidth;
29 | private int mVideoHeight;
30 | private int mVideoSarNum;
31 | private int mVideoSarDen;
32 |
33 | private int mVideoRotationDegree;
34 |
35 | private int mMeasuredWidth;
36 | private int mMeasuredHeight;
37 |
38 | private int mCurrentAspectRatio = IRenderView.AR_ASPECT_FIT_PARENT;
39 |
40 | public MeasureHelper(View view) {
41 | mWeakView = new WeakReference(view);
42 | }
43 |
44 | public View getView() {
45 | if (mWeakView == null)
46 | return null;
47 | return mWeakView.get();
48 | }
49 |
50 | public void setVideoSize(int videoWidth, int videoHeight) {
51 | mVideoWidth = videoWidth;
52 | mVideoHeight = videoHeight;
53 | }
54 |
55 | public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) {
56 | mVideoSarNum = videoSarNum;
57 | mVideoSarDen = videoSarDen;
58 | }
59 |
60 | public void setVideoRotation(int videoRotationDegree) {
61 | mVideoRotationDegree = videoRotationDegree;
62 | }
63 |
64 | /**
65 | * Must be called by View.onMeasure(int, int)
66 | *
67 | * @param widthMeasureSpec
68 | * @param heightMeasureSpec
69 | */
70 | public void doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
71 | //Log.i("@@@@", "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", "
72 | // + MeasureSpec.toString(heightMeasureSpec) + ")");
73 | if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) {
74 | int tempSpec = widthMeasureSpec;
75 | widthMeasureSpec = heightMeasureSpec;
76 | heightMeasureSpec = tempSpec;
77 | }
78 |
79 | int width = View.getDefaultSize(mVideoWidth, widthMeasureSpec);
80 | int height = View.getDefaultSize(mVideoHeight, heightMeasureSpec);
81 | if (mCurrentAspectRatio == IRenderView.AR_MATCH_PARENT) {
82 | width = widthMeasureSpec;
83 | height = heightMeasureSpec;
84 | } else if (mVideoWidth > 0 && mVideoHeight > 0) {
85 | int widthSpecMode = View.MeasureSpec.getMode(widthMeasureSpec);
86 | int widthSpecSize = View.MeasureSpec.getSize(widthMeasureSpec);
87 | int heightSpecMode = View.MeasureSpec.getMode(heightMeasureSpec);
88 | int heightSpecSize = View.MeasureSpec.getSize(heightMeasureSpec);
89 |
90 | if (widthSpecMode == View.MeasureSpec.AT_MOST && heightSpecMode == View.MeasureSpec.AT_MOST) {
91 | float specAspectRatio = (float) widthSpecSize / (float) heightSpecSize;
92 | float displayAspectRatio;
93 | switch (mCurrentAspectRatio) {
94 | case IRenderView.AR_16_9_FIT_PARENT:
95 | displayAspectRatio = 16.0f / 9.0f;
96 | if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270)
97 | displayAspectRatio = 1.0f / displayAspectRatio;
98 | break;
99 | case IRenderView.AR_4_3_FIT_PARENT:
100 | displayAspectRatio = 4.0f / 3.0f;
101 | if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270)
102 | displayAspectRatio = 1.0f / displayAspectRatio;
103 | break;
104 | case IRenderView.AR_ASPECT_FIT_PARENT:
105 | case IRenderView.AR_ASPECT_FILL_PARENT:
106 | case IRenderView.AR_ASPECT_WRAP_CONTENT:
107 | default:
108 | displayAspectRatio = (float) mVideoWidth / (float) mVideoHeight;
109 | if (mVideoSarNum > 0 && mVideoSarDen > 0)
110 | displayAspectRatio = displayAspectRatio * mVideoSarNum / mVideoSarDen;
111 | break;
112 | }
113 | boolean shouldBeWider = displayAspectRatio > specAspectRatio;
114 |
115 | switch (mCurrentAspectRatio) {
116 | case IRenderView.AR_ASPECT_FIT_PARENT:
117 | case IRenderView.AR_16_9_FIT_PARENT:
118 | case IRenderView.AR_4_3_FIT_PARENT:
119 | if (shouldBeWider) {
120 | // too wide, fix width
121 | width = widthSpecSize;
122 | height = (int) (width / displayAspectRatio);
123 | } else {
124 | // too high, fix height
125 | height = heightSpecSize;
126 | width = (int) (height * displayAspectRatio);
127 | }
128 | break;
129 | case IRenderView.AR_ASPECT_FILL_PARENT:
130 | if (shouldBeWider) {
131 | // not high enough, fix height
132 | height = heightSpecSize;
133 | width = (int) (height * displayAspectRatio);
134 | } else {
135 | // not wide enough, fix width
136 | width = widthSpecSize;
137 | height = (int) (width / displayAspectRatio);
138 | }
139 | break;
140 | case IRenderView.AR_ASPECT_WRAP_CONTENT:
141 | default:
142 | if (shouldBeWider) {
143 | // too wide, fix width
144 | width = Math.min(mVideoWidth, widthSpecSize);
145 | height = (int) (width / displayAspectRatio);
146 | } else {
147 | // too high, fix height
148 | height = Math.min(mVideoHeight, heightSpecSize);
149 | width = (int) (height * displayAspectRatio);
150 | }
151 | break;
152 | }
153 | } else if (widthSpecMode == View.MeasureSpec.EXACTLY && heightSpecMode == View.MeasureSpec.EXACTLY) {
154 | // the size is fixed
155 | width = widthSpecSize;
156 | height = heightSpecSize;
157 |
158 | // for compatibility, we adjust size based on aspect ratio
159 | if (mVideoWidth * height < width * mVideoHeight) {
160 | //Log.i("@@@", "image too wide, correcting");
161 | width = height * mVideoWidth / mVideoHeight;
162 | } else if (mVideoWidth * height > width * mVideoHeight) {
163 | //Log.i("@@@", "image too tall, correcting");
164 | height = width * mVideoHeight / mVideoWidth;
165 | }
166 | } else if (widthSpecMode == View.MeasureSpec.EXACTLY) {
167 | // only the width is fixed, adjust the height to match aspect ratio if possible
168 | width = widthSpecSize;
169 | height = width * mVideoHeight / mVideoWidth;
170 | if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) {
171 | // couldn't match aspect ratio within the constraints
172 | height = heightSpecSize;
173 | }
174 | } else if (heightSpecMode == View.MeasureSpec.EXACTLY) {
175 | // only the height is fixed, adjust the width to match aspect ratio if possible
176 | height = heightSpecSize;
177 | width = height * mVideoWidth / mVideoHeight;
178 | if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) {
179 | // couldn't match aspect ratio within the constraints
180 | width = widthSpecSize;
181 | }
182 | } else {
183 | // neither the width nor the height are fixed, try to use actual video size
184 | width = mVideoWidth;
185 | height = mVideoHeight;
186 | if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) {
187 | // too tall, decrease both width and height
188 | height = heightSpecSize;
189 | width = height * mVideoWidth / mVideoHeight;
190 | }
191 | if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) {
192 | // too wide, decrease both width and height
193 | width = widthSpecSize;
194 | height = width * mVideoHeight / mVideoWidth;
195 | }
196 | }
197 | } else {
198 | // no size yet, just adopt the given spec sizes
199 | }
200 |
201 | mMeasuredWidth = width;
202 | mMeasuredHeight = height;
203 | }
204 |
205 | public int getMeasuredWidth() {
206 | return mMeasuredWidth;
207 | }
208 |
209 | public int getMeasuredHeight() {
210 | return mMeasuredHeight;
211 | }
212 |
213 | public void setAspectRatio(int aspectRatio) {
214 | mCurrentAspectRatio = aspectRatio;
215 | }
216 |
217 | @NonNull
218 | public static String getAspectRatioText(Context context, int aspectRatio) {
219 | String text;
220 | switch (aspectRatio) {
221 | case IRenderView.AR_ASPECT_FIT_PARENT:
222 | text = "Aspect / Fit parent";
223 | break;
224 | case IRenderView.AR_ASPECT_FILL_PARENT:
225 | text = "Aspect / Fill parent";
226 | break;
227 | case IRenderView.AR_ASPECT_WRAP_CONTENT:
228 | text = "Aspect / Wrap conten";
229 | break;
230 | case IRenderView.AR_MATCH_PARENT:
231 | text = "Free / Fill parent";
232 | break;
233 | case IRenderView.AR_16_9_FIT_PARENT:
234 | text = "16:9 / Fit parent";
235 | break;
236 | case IRenderView.AR_4_3_FIT_PARENT:
237 | text = "4:3 / Fit parent";
238 | break;
239 | default:
240 | text = "NA";
241 | break;
242 | }
243 | return text;
244 | }
245 | }
246 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/codef/ijkplay_demo/ijkplayer/TextureRenderView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Zhang Rui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.example.codef.ijkplay_demo.ijkplayer;
18 |
19 | import android.annotation.TargetApi;
20 | import android.content.Context;
21 | import android.graphics.SurfaceTexture;
22 | import android.os.Build;
23 | import android.support.annotation.NonNull;
24 | import android.support.annotation.Nullable;
25 | import android.util.AttributeSet;
26 | import android.util.Log;
27 | import android.view.Surface;
28 | import android.view.SurfaceHolder;
29 | import android.view.TextureView;
30 | import android.view.View;
31 | import android.view.accessibility.AccessibilityEvent;
32 | import android.view.accessibility.AccessibilityNodeInfo;
33 |
34 | import java.lang.ref.WeakReference;
35 | import java.util.Map;
36 | import java.util.concurrent.ConcurrentHashMap;
37 |
38 | import tv.danmaku.ijk.media.player.IMediaPlayer;
39 | import tv.danmaku.ijk.media.player.ISurfaceTextureHolder;
40 | import tv.danmaku.ijk.media.player.ISurfaceTextureHost;
41 |
42 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
43 | public class TextureRenderView extends TextureView implements IRenderView {
44 | private static final String TAG = "TextureRenderView";
45 | private MeasureHelper mMeasureHelper;
46 |
47 | public TextureRenderView(Context context) {
48 | super(context);
49 | initView(context);
50 | }
51 |
52 | public TextureRenderView(Context context, AttributeSet attrs) {
53 | super(context, attrs);
54 | initView(context);
55 | }
56 |
57 | public TextureRenderView(Context context, AttributeSet attrs, int defStyleAttr) {
58 | super(context, attrs, defStyleAttr);
59 | initView(context);
60 | }
61 |
62 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
63 | public TextureRenderView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
64 | super(context, attrs, defStyleAttr, defStyleRes);
65 | initView(context);
66 | }
67 |
68 | private void initView(Context context) {
69 | mMeasureHelper = new MeasureHelper(this);
70 | mSurfaceCallback = new SurfaceCallback(this);
71 | setSurfaceTextureListener(mSurfaceCallback);
72 | }
73 |
74 | @Override
75 | public View getView() {
76 | return this;
77 | }
78 |
79 | @Override
80 | public boolean shouldWaitForResize() {
81 | return false;
82 | }
83 |
84 | @Override
85 | protected void onDetachedFromWindow() {
86 | mSurfaceCallback.willDetachFromWindow();
87 | super.onDetachedFromWindow();
88 | mSurfaceCallback.didDetachFromWindow();
89 | }
90 |
91 | //--------------------
92 | // Layout & Measure
93 | //--------------------
94 | @Override
95 | public void setVideoSize(int videoWidth, int videoHeight) {
96 | if (videoWidth > 0 && videoHeight > 0) {
97 | mMeasureHelper.setVideoSize(videoWidth, videoHeight);
98 | requestLayout();
99 | }
100 | }
101 |
102 | @Override
103 | public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) {
104 | if (videoSarNum > 0 && videoSarDen > 0) {
105 | mMeasureHelper.setVideoSampleAspectRatio(videoSarNum, videoSarDen);
106 | requestLayout();
107 | }
108 | }
109 |
110 | @Override
111 | public void setVideoRotation(int degree) {
112 | mMeasureHelper.setVideoRotation(degree);
113 | setRotation(degree);
114 | }
115 |
116 | @Override
117 | public void setAspectRatio(int aspectRatio) {
118 | mMeasureHelper.setAspectRatio(aspectRatio);
119 | requestLayout();
120 | }
121 |
122 | @Override
123 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
124 | mMeasureHelper.doMeasure(widthMeasureSpec, heightMeasureSpec);
125 | setMeasuredDimension(mMeasureHelper.getMeasuredWidth(), mMeasureHelper.getMeasuredHeight());
126 | }
127 |
128 | //--------------------
129 | // TextureViewHolder
130 | //--------------------
131 |
132 | public IRenderView.ISurfaceHolder getSurfaceHolder() {
133 | return new InternalSurfaceHolder(this, mSurfaceCallback.mSurfaceTexture, mSurfaceCallback);
134 | }
135 |
136 | private static final class InternalSurfaceHolder implements IRenderView.ISurfaceHolder {
137 | private TextureRenderView mTextureView;
138 | private SurfaceTexture mSurfaceTexture;
139 | private ISurfaceTextureHost mSurfaceTextureHost;
140 |
141 | public InternalSurfaceHolder(@NonNull TextureRenderView textureView,
142 | @Nullable SurfaceTexture surfaceTexture,
143 | @NonNull ISurfaceTextureHost surfaceTextureHost) {
144 | mTextureView = textureView;
145 | mSurfaceTexture = surfaceTexture;
146 | mSurfaceTextureHost = surfaceTextureHost;
147 | }
148 |
149 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
150 | public void bindToMediaPlayer(IMediaPlayer mp) {
151 | if (mp == null)
152 | return;
153 |
154 | if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) &&
155 | (mp instanceof ISurfaceTextureHolder)) {
156 | ISurfaceTextureHolder textureHolder = (ISurfaceTextureHolder) mp;
157 | mTextureView.mSurfaceCallback.setOwnSurfaceTexture(false);
158 |
159 | SurfaceTexture surfaceTexture = textureHolder.getSurfaceTexture();
160 | if (surfaceTexture != null) {
161 | mTextureView.setSurfaceTexture(surfaceTexture);
162 | } else {
163 | textureHolder.setSurfaceTexture(mSurfaceTexture);
164 | textureHolder.setSurfaceTextureHost(mTextureView.mSurfaceCallback);
165 | }
166 | } else {
167 | mp.setSurface(openSurface());
168 | }
169 | }
170 |
171 | @NonNull
172 | @Override
173 | public IRenderView getRenderView() {
174 | return mTextureView;
175 | }
176 |
177 | @Nullable
178 | @Override
179 | public SurfaceHolder getSurfaceHolder() {
180 | return null;
181 | }
182 |
183 | @Nullable
184 | @Override
185 | public SurfaceTexture getSurfaceTexture() {
186 | return mSurfaceTexture;
187 | }
188 |
189 | @Nullable
190 | @Override
191 | public Surface openSurface() {
192 | if (mSurfaceTexture == null)
193 | return null;
194 | return new Surface(mSurfaceTexture);
195 | }
196 | }
197 |
198 | //-------------------------
199 | // SurfaceHolder.Callback
200 | //-------------------------
201 |
202 | @Override
203 | public void addRenderCallback(IRenderCallback callback) {
204 | mSurfaceCallback.addRenderCallback(callback);
205 | }
206 |
207 | @Override
208 | public void removeRenderCallback(IRenderCallback callback) {
209 | mSurfaceCallback.removeRenderCallback(callback);
210 | }
211 |
212 | private SurfaceCallback mSurfaceCallback;
213 |
214 | private static final class SurfaceCallback implements TextureView.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 | Log.d(TAG, "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 | Log.d(TAG, "releaseSurfaceTexture: null");
310 | } else if (mDidDetachFromWindow) {
311 | if (surfaceTexture != mSurfaceTexture) {
312 | Log.d(TAG, "releaseSurfaceTexture: didDetachFromWindow(): release different SurfaceTexture");
313 | surfaceTexture.release();
314 | } else if (!mOwnSurfaceTexture) {
315 | Log.d(TAG, "releaseSurfaceTexture: didDetachFromWindow(): release detached SurfaceTexture");
316 | surfaceTexture.release();
317 | } else {
318 | Log.d(TAG, "releaseSurfaceTexture: didDetachFromWindow(): already released by TextureView");
319 | }
320 | } else if (mWillDetachFromWindow) {
321 | if (surfaceTexture != mSurfaceTexture) {
322 | Log.d(TAG, "releaseSurfaceTexture: willDetachFromWindow(): release different SurfaceTexture");
323 | surfaceTexture.release();
324 | } else if (!mOwnSurfaceTexture) {
325 | Log.d(TAG, "releaseSurfaceTexture: willDetachFromWindow(): re-attach SurfaceTexture to TextureView");
326 | setOwnSurfaceTexture(true);
327 | } else {
328 | Log.d(TAG, "releaseSurfaceTexture: willDetachFromWindow(): will released by TextureView");
329 | }
330 | } else {
331 | if (surfaceTexture != mSurfaceTexture) {
332 | Log.d(TAG, "releaseSurfaceTexture: alive: release different SurfaceTexture");
333 | surfaceTexture.release();
334 | } else if (!mOwnSurfaceTexture) {
335 | Log.d(TAG, "releaseSurfaceTexture: alive: re-attach SurfaceTexture to TextureView");
336 | setOwnSurfaceTexture(true);
337 | } else {
338 | Log.d(TAG, "releaseSurfaceTexture: alive: will released by TextureView");
339 | }
340 | }
341 | }
342 |
343 | public void willDetachFromWindow() {
344 | Log.d(TAG, "willDetachFromWindow()");
345 | mWillDetachFromWindow = true;
346 | }
347 |
348 | public void didDetachFromWindow() {
349 | Log.d(TAG, "didDetachFromWindow()");
350 | mDidDetachFromWindow = true;
351 | }
352 | }
353 |
354 | //--------------------
355 | // Accessibility
356 | //--------------------
357 |
358 | @Override
359 | public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
360 | super.onInitializeAccessibilityEvent(event);
361 | event.setClassName(TextureRenderView.class.getName());
362 | }
363 |
364 | @Override
365 | public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
366 | super.onInitializeAccessibilityNodeInfo(info);
367 | info.setClassName(TextureRenderView.class.getName());
368 | }
369 | }
370 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/codef/ijkplay_demo/ijkplayer/IjkVideoView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Zhang Rui
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.example.codef.ijkplay_demo.ijkplayer;
18 |
19 | import android.annotation.TargetApi;
20 | import android.content.Context;
21 | import android.content.DialogInterface;
22 | import android.content.res.Resources;
23 | import android.media.AudioManager;
24 | import android.media.MediaPlayer;
25 | import android.net.Uri;
26 | import android.os.Build;
27 | import android.support.annotation.NonNull;
28 | import android.text.TextUtils;
29 | import android.util.AttributeSet;
30 | import android.util.Log;
31 | import android.view.Gravity;
32 | import android.view.KeyEvent;
33 | import android.view.MotionEvent;
34 | import android.view.View;
35 | import android.widget.FrameLayout;
36 | import android.widget.MediaController;
37 |
38 | import java.io.IOException;
39 | import java.util.ArrayList;
40 | import java.util.List;
41 | import java.util.Locale;
42 | import java.util.Map;
43 |
44 | import tv.danmaku.ijk.media.player.AndroidMediaPlayer;
45 | import tv.danmaku.ijk.media.player.IMediaPlayer;
46 | import tv.danmaku.ijk.media.player.IjkMediaPlayer;
47 | import tv.danmaku.ijk.media.player.TextureMediaPlayer;
48 |
49 | public class IjkVideoView extends FrameLayout implements MediaController.MediaPlayerControl {
50 | private String TAG = "IjkVideoView";
51 | // settable by the client
52 | private Uri mUri;
53 | private Map mHeaders;
54 |
55 | // all possible internal states
56 | public static final int STATE_ERROR = -1;
57 | public static final int STATE_IDLE = 0;
58 | public static final int STATE_PREPARING = 1;
59 | public static final int STATE_PREPARED = 2;
60 | public static final int STATE_PLAYING = 3;
61 | public static final int STATE_PAUSED = 4;
62 | public static final int STATE_PLAYBACK_COMPLETED = 5;
63 |
64 | public int getCurrentState() {
65 | return mCurrentState;
66 | }
67 |
68 | // mCurrentState is a VideoView object's current state.
69 | // mTargetState is the state that a method caller intends to reach.
70 | // For instance, regardless the VideoView object's current state,
71 | // calling pause() intends to bring the object to a target state
72 | // of STATE_PAUSED.
73 | private int mCurrentState = STATE_IDLE;
74 | private int mTargetState = STATE_IDLE;
75 |
76 | // All the stuff we need for playing and showing a video
77 | private IRenderView.ISurfaceHolder mSurfaceHolder = null;
78 | private IMediaPlayer mMediaPlayer = null;
79 | // private int mAudioSession;
80 | private int mVideoWidth;
81 | private int mVideoHeight;
82 | private int mSurfaceWidth;
83 | private int mSurfaceHeight;
84 | private int mVideoRotationDegree;
85 | private IMediaController mMediaController;
86 | private IMediaPlayer.OnCompletionListener mOnCompletionListener;
87 | private IMediaPlayer.OnPreparedListener mOnPreparedListener;
88 | private int mCurrentBufferPercentage;
89 | private IMediaPlayer.OnErrorListener mOnErrorListener;
90 | private IMediaPlayer.OnInfoListener mOnInfoListener;
91 | private long mSeekWhenPrepared; // recording the seek position while preparing
92 | private boolean mCanPause = true;
93 | private boolean mCanSeekBack;
94 | private boolean mCanSeekForward;
95 |
96 | /** Subtitle rendering widget overlaid on top of the video. */
97 | // private RenderingWidget mSubtitleWidget;
98 |
99 | /**
100 | * Listener for changes to subtitle data, used to redraw when needed.
101 | */
102 | // private RenderingWidget.OnChangedListener mSubtitlesChangedListener;
103 |
104 | private Context mAppContext;
105 | private IRenderView mRenderView;
106 | private int mVideoSarNum;
107 | private int mVideoSarDen;
108 | private boolean usingAndroidPlayer = false;
109 | private boolean usingMediaCodec = false;
110 | private boolean usingMediaCodecAutoRotate = false;
111 | private boolean usingOpenSLES = false;
112 | private String pixelFormat = "";//Auto Select=,RGB 565=fcc-rv16,RGB 888X=fcc-rv32,YV12=fcc-yv12,默认为RGB 888X
113 | private boolean enableBackgroundPlay = false;
114 | private boolean enableSurfaceView = true;
115 | private boolean enableTextureView = false;
116 | private boolean enableNoView = false;
117 |
118 | public IjkVideoView(Context context) {
119 | super(context);
120 | initVideoView(context);
121 | }
122 |
123 | public IjkVideoView(Context context, AttributeSet attrs) {
124 | super(context, attrs);
125 | initVideoView(context);
126 | }
127 |
128 | public IjkVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
129 | super(context, attrs, defStyleAttr);
130 | initVideoView(context);
131 | }
132 |
133 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
134 | public IjkVideoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
135 | super(context, attrs, defStyleAttr, defStyleRes);
136 | initVideoView(context);
137 | }
138 |
139 | // REMOVED: onMeasure
140 | // REMOVED: onInitializeAccessibilityEvent
141 | // REMOVED: onInitializeAccessibilityNodeInfo
142 | // REMOVED: resolveAdjustedSize
143 |
144 | private void initVideoView(Context context) {
145 | mAppContext = context.getApplicationContext();
146 |
147 | initBackground();
148 | initRenders();
149 |
150 | mVideoWidth = 0;
151 | mVideoHeight = 0;
152 | // REMOVED: getHolder().addCallback(mSHCallback);
153 | // REMOVED: getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
154 | setFocusable(true);
155 | setFocusableInTouchMode(true);
156 | requestFocus();
157 | // REMOVED: mPendingSubtitleTracks = new Vector>();
158 | mCurrentState = STATE_IDLE;
159 | mTargetState = STATE_IDLE;
160 | }
161 |
162 | public void setRenderView(IRenderView renderView) {
163 | if (mRenderView != null) {
164 | if (mMediaPlayer != null)
165 | mMediaPlayer.setDisplay(null);
166 |
167 | View renderUIView = mRenderView.getView();
168 | mRenderView.removeRenderCallback(mSHCallback);
169 | mRenderView = null;
170 | removeView(renderUIView);
171 | }
172 |
173 | if (renderView == null)
174 | return;
175 | mRenderView = renderView;
176 | renderView.setAspectRatio(mCurrentAspectRatio);
177 | if (mVideoWidth > 0 && mVideoHeight > 0)
178 | renderView.setVideoSize(mVideoWidth, mVideoHeight);
179 | if (mVideoSarNum > 0 && mVideoSarDen > 0)
180 | renderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
181 |
182 | View renderUIView = mRenderView.getView();
183 | LayoutParams lp = new LayoutParams(
184 | LayoutParams.WRAP_CONTENT,
185 | LayoutParams.WRAP_CONTENT,
186 | Gravity.CENTER);
187 | renderUIView.setLayoutParams(lp);
188 | addView(renderUIView);
189 |
190 | mRenderView.addRenderCallback(mSHCallback);
191 | mRenderView.setVideoRotation(mVideoRotationDegree);
192 | }
193 |
194 | public void setRender(int render) {
195 | switch (render) {
196 | case RENDER_NONE:
197 | setRenderView(null);
198 | break;
199 | case RENDER_TEXTURE_VIEW: {
200 | TextureRenderView renderView = new TextureRenderView(getContext());
201 | if (mMediaPlayer != null) {
202 | renderView.getSurfaceHolder().bindToMediaPlayer(mMediaPlayer);
203 | renderView.setVideoSize(mMediaPlayer.getVideoWidth(), mMediaPlayer.getVideoHeight());
204 | renderView.setVideoSampleAspectRatio(mMediaPlayer.getVideoSarNum(), mMediaPlayer.getVideoSarDen());
205 | renderView.setAspectRatio(mCurrentAspectRatio);
206 | }
207 | setRenderView(renderView);
208 | break;
209 | }
210 | case RENDER_SURFACE_VIEW: {
211 | SurfaceRenderView renderView = new SurfaceRenderView(getContext());
212 | setRenderView(renderView);
213 | break;
214 | }
215 | default:
216 | Log.e(TAG, String.format(Locale.getDefault(), "invalid render %d\n", render));
217 | break;
218 | }
219 | }
220 |
221 | /**
222 | * Sets video path.
223 | *
224 | * @param path the path of the video.
225 | */
226 | public void setVideoPath(String path) {
227 | setVideoURI(Uri.parse(path));
228 | }
229 |
230 |
231 | public void setHeaders(Map headers) {
232 | mHeaders = headers;
233 | }
234 |
235 | /**
236 | * Sets video URI.
237 | *
238 | * @param uri the URI of the video.
239 | */
240 | public void setVideoURI(Uri uri) {
241 | setVideoURI(uri, mHeaders);
242 | }
243 |
244 | /**
245 | * Sets video URI using specific headers.
246 | *
247 | * @param uri the URI of the video.
248 | * @param headers the headers for the URI request.
249 | * Note that the cross domain redirection is allowed by default, but that can be
250 | * changed with key/value pairs through the headers parameter with
251 | * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value
252 | * to disallow or allow cross domain redirection.
253 | */
254 | public void setVideoURI(Uri uri, Map headers) {
255 | mUri = uri;
256 | mHeaders = headers;
257 | mSeekWhenPrepared = 0;
258 | openVideo();
259 | requestLayout();
260 | invalidate();
261 | }
262 |
263 | // REMOVED: addSubtitleSource
264 | // REMOVED: mPendingSubtitleTracks
265 |
266 | public void stopPlayback() {
267 | if (mMediaPlayer != null) {
268 | mMediaPlayer.stop();
269 | mMediaPlayer.release();
270 | mMediaPlayer = null;
271 | mCurrentState = STATE_IDLE;
272 | mTargetState = STATE_IDLE;
273 | AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);
274 | am.abandonAudioFocus(null);
275 | }
276 | }
277 |
278 | private void openVideo() {
279 | if (mUri == null || mSurfaceHolder == null) {
280 | // not ready for playback just yet, will try again later
281 | return;
282 | }
283 | // we shouldn't clear the target state, because somebody might have
284 | // called start() previously
285 | release(false);
286 |
287 | AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);
288 | am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
289 |
290 | try {
291 | if (usingAndroidPlayer) {
292 | mMediaPlayer = new AndroidMediaPlayer();
293 | } else {
294 | IjkMediaPlayer ijkMediaPlayer = null;
295 | if (mUri != null) {
296 | ijkMediaPlayer = new IjkMediaPlayer();
297 | ijkMediaPlayer.native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG);
298 |
299 | if (usingMediaCodec) {
300 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
301 | if (usingMediaCodecAutoRotate) {
302 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1);
303 | } else {
304 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 0);
305 | }
306 | } else {
307 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 0);
308 | }
309 |
310 | if (usingOpenSLES) {
311 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 1);
312 | } else {
313 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 0);
314 | }
315 |
316 | if (TextUtils.isEmpty(pixelFormat)) {
317 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", IjkMediaPlayer.SDL_FCC_RV32);
318 | } else {
319 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", pixelFormat);
320 | }
321 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 1);
322 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 0);
323 |
324 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "http-detect-range-support", 0);
325 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "timeout", 10000000);
326 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "reconnect", 1);
327 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-hevc", 1);
328 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "safe", 0);
329 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "protocol_whitelist", "async,cache,crypto,file,http,https,ijkhttphook,ijkinject,ijklivehook,ijklongurl," +
330 | "ijksegment,ijktcphook,pipe,rtp,tcp,tls,udp,ijkurlhook,data,concat,subfile,udp");
331 |
332 | ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 48);
333 | }
334 | mMediaPlayer = ijkMediaPlayer;
335 | }
336 |
337 | if (enableBackgroundPlay) {
338 | mMediaPlayer = new TextureMediaPlayer(mMediaPlayer);
339 | }
340 |
341 | // TODO: create SubtitleController in MediaPlayer, but we need
342 | // a context for the subtitle renderers
343 | final Context context = getContext();
344 | // REMOVED: SubtitleController
345 |
346 | // REMOVED: mAudioSession
347 | mMediaPlayer.setOnPreparedListener(mPreparedListener);
348 | mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
349 | mMediaPlayer.setOnCompletionListener(mCompletionListener);
350 | mMediaPlayer.setOnErrorListener(mErrorListener);
351 | mMediaPlayer.setOnInfoListener(mInfoListener);
352 | mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
353 | mCurrentBufferPercentage = 0;
354 | if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
355 | mMediaPlayer.setDataSource(mAppContext, mUri, mHeaders);
356 | } else {
357 | mMediaPlayer.setDataSource(mUri.toString());
358 | }
359 | bindSurfaceHolder(mMediaPlayer, mSurfaceHolder);
360 | mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
361 | mMediaPlayer.setScreenOnWhilePlaying(true);
362 | mMediaPlayer.prepareAsync();
363 |
364 | // REMOVED: mPendingSubtitleTracks
365 |
366 | // we don't set the target state here either, but preserve the
367 | // target state that was there before.
368 | mCurrentState = STATE_PREPARING;
369 | attachMediaController();
370 | } catch (IOException ex) {
371 | Log.w(TAG, "Unable to open content: " + mUri, ex);
372 | mCurrentState = STATE_ERROR;
373 | mTargetState = STATE_ERROR;
374 | mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
375 | return;
376 | } catch (IllegalArgumentException ex) {
377 | Log.w(TAG, "Unable to open content: " + mUri, ex);
378 | mCurrentState = STATE_ERROR;
379 | mTargetState = STATE_ERROR;
380 | mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
381 | return;
382 | } finally {
383 | // REMOVED: mPendingSubtitleTracks.clear();
384 | }
385 | }
386 |
387 | public void setMediaController(IMediaController controller) {
388 | if (mMediaController != null) {
389 | mMediaController.hide();
390 | }
391 | mMediaController = controller;
392 | attachMediaController();
393 | }
394 |
395 | private void attachMediaController() {
396 | if (mMediaPlayer != null && mMediaController != null) {
397 | mMediaController.setMediaPlayer(this);
398 | View anchorView = this.getParent() instanceof View ?
399 | (View) this.getParent() : this;
400 | mMediaController.setAnchorView(anchorView);
401 | mMediaController.setEnabled(isInPlaybackState());
402 | }
403 | }
404 |
405 | IMediaPlayer.OnVideoSizeChangedListener mSizeChangedListener =
406 | new IMediaPlayer.OnVideoSizeChangedListener() {
407 | public void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sarNum, int sarDen) {
408 | mVideoWidth = mp.getVideoWidth();
409 | mVideoHeight = mp.getVideoHeight();
410 | mVideoSarNum = mp.getVideoSarNum();
411 | mVideoSarDen = mp.getVideoSarDen();
412 | if (mVideoWidth != 0 && mVideoHeight != 0) {
413 | if (mRenderView != null) {
414 | mRenderView.setVideoSize(mVideoWidth, mVideoHeight);
415 | mRenderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
416 | }
417 | // REMOVED: getHolder().setFixedSize(mVideoWidth, mVideoHeight);
418 | requestLayout();
419 | }
420 | }
421 | };
422 |
423 | IMediaPlayer.OnPreparedListener mPreparedListener = new IMediaPlayer.OnPreparedListener() {
424 | public void onPrepared(IMediaPlayer mp) {
425 | mCurrentState = STATE_PREPARED;
426 |
427 | // Get the capabilities of the player for this stream
428 | // REMOVED: Metadata
429 |
430 | if (mOnPreparedListener != null) {
431 | mOnPreparedListener.onPrepared(mMediaPlayer);
432 | }
433 | if (mMediaController != null) {
434 | mMediaController.setEnabled(true);
435 | }
436 | mVideoWidth = mp.getVideoWidth();
437 | mVideoHeight = mp.getVideoHeight();
438 |
439 | long seekToPosition = mSeekWhenPrepared; // mSeekWhenPrepared may be changed after seekTo() call
440 | if (seekToPosition != 0) {
441 | seekTo((int) seekToPosition);
442 | }
443 | if (mVideoWidth != 0 && mVideoHeight != 0) {
444 | //Log.i("@@@@", "video size: " + mVideoWidth +"/"+ mVideoHeight);
445 | // REMOVED: getHolder().setFixedSize(mVideoWidth, mVideoHeight);
446 | if (mRenderView != null) {
447 | mRenderView.setVideoSize(mVideoWidth, mVideoHeight);
448 | mRenderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
449 | if (!mRenderView.shouldWaitForResize() || mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) {
450 | // We didn't actually change the size (it was already at the size
451 | // we need), so we won't get a "surface changed" callback, so
452 | // start the video here instead of in the callback.
453 | if (mTargetState == STATE_PLAYING) {
454 | start();
455 | if (mMediaController != null) {
456 | mMediaController.show();
457 | }
458 | } else if (!isPlaying() &&
459 | (seekToPosition != 0 || getCurrentPosition() > 0)) {
460 | if (mMediaController != null) {
461 | // Show the media controls when we're paused into a video and make 'em stick.
462 | mMediaController.show(0);
463 | }
464 | }
465 | }
466 | }
467 | } else {
468 | // We don't know the video size yet, but should start anyway.
469 | // The video size might be reported to us later.
470 | if (mTargetState == STATE_PLAYING) {
471 | start();
472 | }
473 | }
474 | }
475 | };
476 |
477 | private IMediaPlayer.OnCompletionListener mCompletionListener =
478 | new IMediaPlayer.OnCompletionListener() {
479 | public void onCompletion(IMediaPlayer mp) {
480 | mCurrentState = STATE_PLAYBACK_COMPLETED;
481 | mTargetState = STATE_PLAYBACK_COMPLETED;
482 | if (mMediaController != null) {
483 | mMediaController.hide();
484 | }
485 | if (mOnCompletionListener != null) {
486 | mOnCompletionListener.onCompletion(mMediaPlayer);
487 | }
488 | }
489 | };
490 |
491 | private IMediaPlayer.OnInfoListener mInfoListener =
492 | new IMediaPlayer.OnInfoListener() {
493 | public boolean onInfo(IMediaPlayer mp, int arg1, int arg2) {
494 | if (mOnInfoListener != null) {
495 | mOnInfoListener.onInfo(mp, arg1, arg2);
496 | }
497 | switch (arg1) {
498 | case IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED:
499 | mVideoRotationDegree = arg2;
500 | Log.d(TAG, "MEDIA_INFO_VIDEO_ROTATION_CHANGED: " + arg2);
501 | if (mRenderView != null)
502 | mRenderView.setVideoRotation(arg2);
503 | break;
504 | }
505 | return true;
506 | }
507 | };
508 |
509 | private IMediaPlayer.OnErrorListener mErrorListener =
510 | new IMediaPlayer.OnErrorListener() {
511 | public boolean onError(IMediaPlayer mp, int framework_err, int impl_err) {
512 | Log.d(TAG, "Error: " + framework_err + "," + impl_err);
513 | mCurrentState = STATE_ERROR;
514 | mTargetState = STATE_ERROR;
515 | if (mMediaController != null) {
516 | mMediaController.hide();
517 | }
518 |
519 | /* If an error handler has been supplied, use it and finish. */
520 | if (mOnErrorListener != null) {
521 | if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) {
522 | return true;
523 | }
524 | }
525 |
526 | /* Otherwise, pop up an error dialog so the user knows that
527 | * something bad has happened. Only try and pop up the dialog
528 | * if we're attached to a window. When we're going away and no
529 | * longer have a window, don't bother showing the user an error.
530 | */
531 | if (getWindowToken() != null) {
532 | Resources r = mAppContext.getResources();
533 | String message = "Unknown error";
534 |
535 | // if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
536 | // message = "Invalid progressive playback";
537 | // }
538 | //
539 | // new android.app.AlertDialog.Builder(getContext())
540 | // .setMessage(message)
541 | // .setPositiveButton("error",
542 | // new DialogInterface.OnClickListener() {
543 | // public void onClick(DialogInterface dialog, int whichButton) {
544 | // /* If we get here, there is no onError listener, so
545 | // * at least inform them that the video is over.
546 | // */
547 | // if (mOnCompletionListener != null) {
548 | // mOnCompletionListener.onCompletion(mMediaPlayer);
549 | // }
550 | // }
551 | // })
552 | // .setCancelable(false)
553 | // .show();
554 | }
555 | return true;
556 | }
557 | };
558 |
559 | private IMediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener =
560 | new IMediaPlayer.OnBufferingUpdateListener() {
561 | public void onBufferingUpdate(IMediaPlayer mp, int percent) {
562 | mCurrentBufferPercentage = percent;
563 | }
564 | };
565 |
566 | /**
567 | * Register a callback to be invoked when the media file
568 | * is loaded and ready to go.
569 | *
570 | * @param l The callback that will be run
571 | */
572 | public void setOnPreparedListener(IMediaPlayer.OnPreparedListener l) {
573 | mOnPreparedListener = l;
574 | }
575 |
576 | /**
577 | * Register a callback to be invoked when the end of a media file
578 | * has been reached during playback.
579 | *
580 | * @param l The callback that will be run
581 | */
582 | public void setOnCompletionListener(IMediaPlayer.OnCompletionListener l) {
583 | mOnCompletionListener = l;
584 | }
585 |
586 | /**
587 | * Register a callback to be invoked when an error occurs
588 | * during playback or setup. If no listener is specified,
589 | * or if the listener returned false, VideoView will inform
590 | * the user of any errors.
591 | *
592 | * @param l The callback that will be run
593 | */
594 | public void setOnErrorListener(IMediaPlayer.OnErrorListener l) {
595 | mOnErrorListener = l;
596 | }
597 |
598 | /**
599 | * Register a callback to be invoked when an informational event
600 | * occurs during playback or setup.
601 | *
602 | * @param l The callback that will be run
603 | */
604 | public void setOnInfoListener(IMediaPlayer.OnInfoListener l) {
605 | mOnInfoListener = l;
606 | }
607 |
608 | // REMOVED: mSHCallback
609 | private void bindSurfaceHolder(IMediaPlayer mp, IRenderView.ISurfaceHolder holder) {
610 | if (mp == null)
611 | return;
612 |
613 | if (holder == null) {
614 | mp.setDisplay(null);
615 | return;
616 | }
617 |
618 | holder.bindToMediaPlayer(mp);
619 | }
620 |
621 | IRenderView.IRenderCallback mSHCallback = new IRenderView.IRenderCallback() {
622 | @Override
623 | public void onSurfaceChanged(@NonNull IRenderView.ISurfaceHolder holder, int format, int w, int h) {
624 | if (holder.getRenderView() != mRenderView) {
625 | Log.e(TAG, "onSurfaceChanged: unmatched render callback\n");
626 | return;
627 | }
628 |
629 | mSurfaceWidth = w;
630 | mSurfaceHeight = h;
631 | boolean isValidState = (mTargetState == STATE_PLAYING);
632 | boolean hasValidSize = !mRenderView.shouldWaitForResize() || (mVideoWidth == w && mVideoHeight == h);
633 | if (mMediaPlayer != null && isValidState && hasValidSize) {
634 | if (mSeekWhenPrepared != 0) {
635 | seekTo((int) mSeekWhenPrepared);
636 | }
637 | start();
638 | }
639 | }
640 |
641 | @Override
642 | public void onSurfaceCreated(@NonNull IRenderView.ISurfaceHolder holder, int width, int height) {
643 | if (holder.getRenderView() != mRenderView) {
644 | Log.e(TAG, "onSurfaceCreated: unmatched render callback\n");
645 | return;
646 | }
647 |
648 | mSurfaceHolder = holder;
649 | if (mMediaPlayer != null)
650 | bindSurfaceHolder(mMediaPlayer, holder);
651 | else
652 | openVideo();
653 | }
654 |
655 | @Override
656 | public void onSurfaceDestroyed(@NonNull IRenderView.ISurfaceHolder holder) {
657 | if (holder.getRenderView() != mRenderView) {
658 | Log.e(TAG, "onSurfaceDestroyed: unmatched render callback\n");
659 | return;
660 | }
661 |
662 | // after we return from this we can't use the surface any more
663 | mSurfaceHolder = null;
664 | // REMOVED: if (mMediaController != null) mMediaController.hide();
665 | // REMOVED: release(true);
666 | releaseWithoutStop();
667 | }
668 | };
669 |
670 | public void releaseWithoutStop() {
671 | if (mMediaPlayer != null)
672 | mMediaPlayer.setDisplay(null);
673 | }
674 |
675 | /*
676 | * release the media player in any state
677 | */
678 | public void release(boolean cleartargetstate) {
679 | if (mMediaPlayer != null) {
680 | mMediaPlayer.reset();
681 | mMediaPlayer.release();
682 | mMediaPlayer = null;
683 | // REMOVED: mPendingSubtitleTracks.clear();
684 | mCurrentState = STATE_IDLE;
685 | if (cleartargetstate) {
686 | mTargetState = STATE_IDLE;
687 | }
688 | AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);
689 | am.abandonAudioFocus(null);
690 | }
691 | }
692 |
693 | @Override
694 | public boolean onTouchEvent(MotionEvent ev) {
695 | if (isInPlaybackState() && mMediaController != null) {
696 | toggleMediaControlsVisiblity();
697 | }
698 | return false;
699 | }
700 |
701 | @Override
702 | public boolean onTrackballEvent(MotionEvent ev) {
703 | if (isInPlaybackState() && mMediaController != null) {
704 | toggleMediaControlsVisiblity();
705 | }
706 | return false;
707 | }
708 |
709 | @Override
710 | public boolean onKeyDown(int keyCode, KeyEvent event) {
711 | boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK &&
712 | keyCode != KeyEvent.KEYCODE_VOLUME_UP &&
713 | keyCode != KeyEvent.KEYCODE_VOLUME_DOWN &&
714 | keyCode != KeyEvent.KEYCODE_VOLUME_MUTE &&
715 | keyCode != KeyEvent.KEYCODE_MENU &&
716 | keyCode != KeyEvent.KEYCODE_CALL &&
717 | keyCode != KeyEvent.KEYCODE_ENDCALL;
718 | if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) {
719 | if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK ||
720 | keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
721 | if (mMediaPlayer.isPlaying()) {
722 | pause();
723 | mMediaController.show();
724 | } else {
725 | start();
726 | mMediaController.hide();
727 | }
728 | return true;
729 | } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
730 | if (!mMediaPlayer.isPlaying()) {
731 | start();
732 | mMediaController.hide();
733 | }
734 | return true;
735 | } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
736 | || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
737 | if (mMediaPlayer.isPlaying()) {
738 | pause();
739 | mMediaController.show();
740 | }
741 | return true;
742 | } else {
743 | toggleMediaControlsVisiblity();
744 | }
745 | }
746 |
747 | return super.onKeyDown(keyCode, event);
748 | }
749 |
750 | private void toggleMediaControlsVisiblity() {
751 | if (mMediaController.isShowing()) {
752 | mMediaController.hide();
753 | } else {
754 | mMediaController.show();
755 | }
756 | }
757 |
758 | @Override
759 | public void start() {
760 | if (isInPlaybackState()) {
761 | mMediaPlayer.start();
762 | mCurrentState = STATE_PLAYING;
763 | }
764 | mTargetState = STATE_PLAYING;
765 | }
766 |
767 | @Override
768 | public void pause() {
769 | if (isInPlaybackState()) {
770 | if (mMediaPlayer.isPlaying()) {
771 | mMediaPlayer.pause();
772 | mCurrentState = STATE_PAUSED;
773 | }
774 | }
775 | mTargetState = STATE_PAUSED;
776 | }
777 |
778 | public void suspend() {
779 | release(false);
780 | }
781 |
782 | public void resume() {
783 | openVideo();
784 | }
785 |
786 | @Override
787 | public int getDuration() {
788 | if (isInPlaybackState()) {
789 | return (int) mMediaPlayer.getDuration();
790 | }
791 |
792 | return -1;
793 | }
794 |
795 | @Override
796 | public int getCurrentPosition() {
797 | if (isInPlaybackState()) {
798 | return (int) mMediaPlayer.getCurrentPosition();
799 | }
800 | return 0;
801 | }
802 |
803 | @Override
804 | public void seekTo(int msec) {
805 | if (isInPlaybackState()) {
806 | mMediaPlayer.seekTo(msec);
807 | mSeekWhenPrepared = 0;
808 | } else {
809 | mSeekWhenPrepared = msec;
810 | }
811 | }
812 |
813 | @Override
814 | public boolean isPlaying() {
815 | return isInPlaybackState() && mMediaPlayer.isPlaying();
816 | }
817 |
818 | @Override
819 | public int getBufferPercentage() {
820 | if (mMediaPlayer != null) {
821 | return mCurrentBufferPercentage;
822 | }
823 | return 0;
824 | }
825 |
826 | private boolean isInPlaybackState() {
827 | return (mMediaPlayer != null &&
828 | mCurrentState != STATE_ERROR &&
829 | mCurrentState != STATE_IDLE &&
830 | mCurrentState != STATE_PREPARING);
831 | }
832 |
833 | @Override
834 | public boolean canPause() {
835 | return mCanPause;
836 | }
837 |
838 | @Override
839 | public boolean canSeekBackward() {
840 | return mCanSeekBack;
841 | }
842 |
843 | @Override
844 | public boolean canSeekForward() {
845 | return mCanSeekForward;
846 | }
847 |
848 | @Override
849 | public int getAudioSessionId() {
850 | return 0;
851 | }
852 |
853 | // REMOVED: getAudioSessionId();
854 | // REMOVED: onAttachedToWindow();
855 | // REMOVED: onDetachedFromWindow();
856 | // REMOVED: onLayout();
857 | // REMOVED: draw();
858 | // REMOVED: measureAndLayoutSubtitleWidget();
859 | // REMOVED: setSubtitleWidget();
860 | // REMOVED: getSubtitleLooper();
861 |
862 | //-------------------------
863 | // Extend: Aspect Ratio
864 | //-------------------------
865 |
866 | private static final int[] s_allAspectRatio = {
867 | IRenderView.AR_ASPECT_FIT_PARENT,
868 | IRenderView.AR_ASPECT_FILL_PARENT,
869 | IRenderView.AR_ASPECT_WRAP_CONTENT,
870 | IRenderView.AR_MATCH_PARENT,
871 | IRenderView.AR_16_9_FIT_PARENT,
872 | IRenderView.AR_4_3_FIT_PARENT};
873 | private int mCurrentAspectRatioIndex = 0;
874 | private int mCurrentAspectRatio = s_allAspectRatio[mCurrentAspectRatioIndex];
875 |
876 | public int toggleAspectRatio() {
877 | mCurrentAspectRatioIndex++;
878 | mCurrentAspectRatioIndex %= s_allAspectRatio.length;
879 |
880 | mCurrentAspectRatio = s_allAspectRatio[mCurrentAspectRatioIndex];
881 | if (mRenderView != null)
882 | mRenderView.setAspectRatio(mCurrentAspectRatio);
883 | return mCurrentAspectRatio;
884 | }
885 |
886 | public int toggleAspectRatio(int aspect_ratio) {
887 | aspect_ratio %= s_allAspectRatio.length;
888 | mCurrentAspectRatio = s_allAspectRatio[aspect_ratio];
889 | if (mRenderView != null)
890 | mRenderView.setAspectRatio(mCurrentAspectRatio);
891 | return mCurrentAspectRatio;
892 | }
893 |
894 | //-------------------------
895 | // Extend: Render
896 | //-------------------------
897 | public static final int RENDER_NONE = 0;
898 | public static final int RENDER_SURFACE_VIEW = 1;
899 | public static final int RENDER_TEXTURE_VIEW = 2;
900 |
901 | private List mAllRenders = new ArrayList();
902 | private int mCurrentRenderIndex = 0;
903 | private int mCurrentRender = RENDER_NONE;
904 |
905 | private void initRenders() {
906 | mAllRenders.clear();
907 |
908 | if (enableSurfaceView)
909 | mAllRenders.add(RENDER_SURFACE_VIEW);
910 | if (enableTextureView && Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
911 | mAllRenders.add(RENDER_TEXTURE_VIEW);
912 | if (enableNoView)
913 | mAllRenders.add(RENDER_NONE);
914 |
915 | if (mAllRenders.isEmpty())
916 | mAllRenders.add(RENDER_SURFACE_VIEW);
917 | mCurrentRender = mAllRenders.get(mCurrentRenderIndex);
918 | setRender(mCurrentRender);
919 | }
920 |
921 | public int toggleRender() {
922 | mCurrentRenderIndex++;
923 | mCurrentRenderIndex %= mAllRenders.size();
924 |
925 | mCurrentRender = mAllRenders.get(mCurrentRenderIndex);
926 | setRender(mCurrentRender);
927 | return mCurrentRender;
928 | }
929 |
930 |
931 | //-------------------------
932 | // Extend: Background
933 | //-------------------------
934 |
935 |
936 | private void initBackground() {
937 | if (enableBackgroundPlay) {
938 | // MediaPlayerService.intentToStart(getContext());
939 | // mMediaPlayer = MediaPlayerService.getMediaPlayer();
940 | }
941 | }
942 |
943 | public void setAspectRatio(int aspectRatio) {
944 | for (int i = 0; i < s_allAspectRatio.length; i++) {
945 | if (s_allAspectRatio[i] == aspectRatio) {
946 | mCurrentAspectRatioIndex = i;
947 | if (mRenderView != null) {
948 | mRenderView.setAspectRatio(mCurrentAspectRatio);
949 | }
950 | break;
951 | }
952 | }
953 | }
954 | }
955 |
956 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/codef/ijkplay_demo/ijkplayer/ijkvideo.java:
--------------------------------------------------------------------------------
1 | package com.example.codef.ijkplay_demo.ijkplayer;
2 |
3 | import android.app.Activity;
4 | import android.app.Application;
5 | import android.content.ContentResolver;
6 | import android.content.Context;
7 | import android.content.pm.ActivityInfo;
8 | import android.content.res.Resources;
9 | import android.media.AudioManager;
10 | import android.os.Build;
11 | import android.os.Bundle;
12 | import android.os.Handler;
13 | import android.os.Message;
14 | import android.provider.Settings;
15 | import android.util.DisplayMetrics;
16 | import android.util.Log;
17 | import android.view.GestureDetector;
18 | import android.view.KeyEvent;
19 | import android.view.LayoutInflater;
20 | import android.view.MotionEvent;
21 | import android.view.View;
22 | import android.view.ViewGroup;
23 | import android.view.Window;
24 | import android.view.WindowManager;
25 | import android.widget.AdapterView;
26 | import android.widget.ArrayAdapter;
27 | import android.widget.Button;
28 | import android.widget.FrameLayout;
29 | import android.widget.ImageButton;
30 | import android.widget.ImageView;
31 | import android.widget.LinearLayout;
32 | import android.widget.ListView;
33 | import android.widget.ProgressBar;
34 | import android.widget.RelativeLayout;
35 | import android.widget.SeekBar;
36 | import android.widget.TextView;
37 |
38 | import com.example.codef.ijkplay_demo.R;
39 |
40 | import java.io.BufferedReader;
41 | import java.io.File;
42 | import java.io.FileOutputStream;
43 | import java.io.IOException;
44 | import java.io.InputStream;
45 | import java.io.InputStreamReader;
46 | import java.lang.reflect.Field;
47 | import java.net.HttpURLConnection;
48 | import java.net.MalformedURLException;
49 | import java.net.URL;
50 | import java.util.HashMap;
51 | import java.util.Map;
52 | import java.util.Timer;
53 | import java.util.TimerTask;
54 | import java.util.regex.Matcher;
55 | import java.util.regex.Pattern;
56 |
57 | import tv.danmaku.ijk.media.player.IMediaPlayer;
58 | import tv.danmaku.ijk.media.player.IjkMediaPlayer;
59 |
60 | /**
61 | * Created by codef on 2017/8/14.
62 | */
63 |
64 | public class ijkvideo {
65 | private static final String TAG = "ijkvideo";
66 | private ImageButton fullButton;
67 | private TextView mTitleText;
68 | private ImageButton playBack;
69 | private TextView playTime;
70 | private TextView playAllTime;
71 | private myGestureListener mGesture;
72 | private RelativeLayout mViewLight;
73 | private RelativeLayout mViewSound;
74 | private RelativeLayout mStatus;
75 | private ProgressBar barLight;
76 | private ProgressBar barSound;
77 | private ImageView loadingView;
78 | private Button sharBtn;
79 | private ListView sharList;
80 | private LinearLayout sharLayout;
81 | private Map mHeaders;
82 |
83 | public ijkvideo(Context context) {
84 | mContext = context;
85 | mHeaders = new HashMap<>();
86 | initView();
87 | }
88 |
89 | private IjkVideoView mVideoView = null;
90 | private RelativeLayout mViewHolder = null;
91 | private Context mContext = null;
92 | private int mWidth, mHeight, mLeft, mTop;
93 |
94 | private ImageButton playButton;
95 | private SeekBar seekBar;
96 | private LinearLayout mPlayTop, mPlayController;
97 | private RelativeLayout sharBtnLayout;
98 |
99 | private void initView() {
100 | //init player
101 | IjkMediaPlayer.loadLibrariesOnce(null);
102 | IjkMediaPlayer.native_profileBegin("libijkplayer.so");
103 | mLeft = 0;
104 | mTop = 0;
105 | Resources resources = mContext.getResources();
106 | DisplayMetrics dm = resources.getDisplayMetrics();
107 | mWidth = dm.widthPixels;
108 | mHeight = (int) (mWidth * 0.5);
109 | }
110 |
111 | private boolean isAllShow = true;
112 |
113 | public void hideControls(boolean show) {
114 | isAllShow = show;
115 | }
116 |
117 | public int getLeft() {
118 | return mLeft;
119 | }
120 |
121 | public int getTop() {
122 | return mTop;
123 | }
124 |
125 | public int getHeight() {
126 | return mHeight;
127 | }
128 |
129 | public int getWidth() {
130 | return mWidth;
131 | }
132 |
133 | /**
134 | * 通过反射的方式获取状态栏高度
135 | *
136 | * @return
137 | */
138 | private int getStatusBarHeight() {
139 | try {
140 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
141 | if ((WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS & ((Activity) mContext).getWindow().getAttributes().flags)
142 | == WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) {
143 | Class> c = Class.forName("com.android.internal.R$dimen");
144 | Object obj = c.newInstance();
145 | Field field = c.getField("status_bar_height");
146 | int x = Integer.parseInt(field.get(obj).toString());
147 | return mContext.getResources().getDimensionPixelSize(x);
148 | }
149 | }
150 | } catch (Exception e) {
151 | e.printStackTrace();
152 | }
153 | return 0;
154 | }
155 |
156 | public GestureDetector mGestureDetector;
157 |
158 | public View createPlayer(int left, int top, int width, int height) {
159 | mWidth = width;
160 | mHeight = height;
161 | mTop = top;
162 | mLeft = left;
163 | return createPlayer();
164 | }
165 |
166 | private View playView;
167 |
168 | public void setTitle(String title) {
169 | mTitleText.setText(title);
170 | }
171 |
172 | public View createPlayer() {
173 | isCreate = true;
174 | LayoutInflater inflater = LayoutInflater.from(mContext);
175 | playView = inflater.inflate(R.layout.play, null);
176 | mViewHolder = (RelativeLayout) playView.findViewById(R.id.combineCtrl);
177 | mVideoView = (IjkVideoView) mViewHolder.findViewById(R.id.video_view);
178 | mPlayTop = (LinearLayout) mViewHolder.findViewById(R.id.play_top);
179 | mPlayController = (LinearLayout) mViewHolder.findViewById(R.id.play_controller);
180 | mViewLight = (RelativeLayout) mViewHolder.findViewById(R.id.view_light);
181 | mViewLight.setVisibility(View.GONE);
182 | barLight = (ProgressBar) mViewHolder.findViewById(R.id.bar_light);
183 | mViewSound = (RelativeLayout) mViewHolder.findViewById(R.id.view_sound);
184 | mViewSound.setVisibility(View.GONE);
185 | barSound = (ProgressBar) mViewHolder.findViewById(R.id.bar_sound);
186 | playTime = (TextView) mViewHolder.findViewById(R.id.now_time);
187 | playAllTime = (TextView) mViewHolder.findViewById(R.id.all_time);
188 | mTitleText = (TextView) mViewHolder.findViewById(R.id.play_title);
189 | mStatus = (RelativeLayout) mViewHolder.findViewById(R.id.statusLayout);
190 | mStatus.setVisibility(View.GONE);
191 | loadingView = (ImageView) mViewHolder.findViewById(R.id.loading);
192 | sharLayout = (LinearLayout) mViewHolder.findViewById(R.id.shar_layout);
193 | sharLayout.setVisibility(View.GONE);
194 | sharBtn = (Button) mViewHolder.findViewById(R.id.shar_btn);
195 | sharList = (ListView) mViewHolder.findViewById(R.id.shar_list);
196 | sharBtnLayout = (RelativeLayout) mViewHolder.findViewById(R.id.shar_btn_layout);
197 | sharBtnLayout.setVisibility(View.GONE);
198 | // android.R.layout.simple_list_item_1;
199 | aptShar = new ArrayAdapter(((Activity) mContext), R.layout.shar_list_text_item);
200 | sharList.setAdapter(aptShar);
201 | // String[] datas = {"4K","蓝光(1080P)", "高清", "流畅"};
202 | // sharList.setAdapter(new ArrayAdapter(((Activity) mContext), R.layout.shar_list_item, datas));
203 | // sharList.setSelection(1);
204 |
205 | FrameLayout.LayoutParams rllp = new FrameLayout.LayoutParams(mWidth, mHeight);
206 | rllp.leftMargin = mLeft;
207 | rllp.topMargin = mTop;
208 | ((Activity) mContext).addContentView(mViewHolder, rllp);
209 | toggleAspectRatio(1);
210 | mGesture = new myGestureListener();
211 | mGestureDetector = new GestureDetector(mViewHolder.getContext(), mGesture);
212 | mViewHolder.setOnTouchListener(new View.OnTouchListener() {
213 | @Override
214 | public boolean onTouch(View view, MotionEvent motionEvent) {
215 | if (motionEvent.getAction() == 1 && mGesture.isScroll) {//GestureDetector的onScroll竟然不会触发手指抬起事件,只好自己来实现了
216 | return mGesture.onSingleTapUp(motionEvent);
217 | }
218 | return mGestureDetector.onTouchEvent(motionEvent);
219 | }
220 | });
221 | mVideoView.setOnKeyListener(new View.OnKeyListener() {
222 | @Override
223 | public boolean onKey(View v, int keyCode, KeyEvent event) {
224 | switch (keyCode) {
225 | case KeyEvent.KEYCODE_BACK: {
226 | if (isFull) {
227 | fullScreen();
228 | return true;
229 | }
230 | }
231 | }
232 | return false;
233 | }
234 | });
235 | playButton = (ImageButton) mViewHolder.findViewById(R.id.play_play);
236 | playButton.setOnClickListener(new Button.OnClickListener() {
237 | public void onClick(View v) {
238 | if (mVideoView != null) {
239 | if (isPlaying()) {
240 | pause();
241 | } else {
242 | start();
243 | }
244 | show();
245 | }
246 | }
247 | });
248 | sharBtn.setOnClickListener(new View.OnClickListener() {
249 | @Override
250 | public void onClick(View v) {
251 | if (mVideoView != null) {
252 | hidden();
253 | sharList.postDelayed(new Runnable() {
254 | @Override
255 | public void run() {
256 | sharList.requestFocusFromTouch();
257 | sharList.setSelection(sharSelectIndex);
258 | }
259 | }, 50);
260 | sharLayout.setVisibility(View.VISIBLE);
261 | }
262 | }
263 | });
264 | playBack = (ImageButton) mViewHolder.findViewById(R.id.play_back);
265 | playBack.setOnClickListener(new Button.OnClickListener() {
266 | public void onClick(View v) {
267 | if (isFull) {
268 | fullScreen();
269 | } else {
270 | try {
271 | Runtime runtime = Runtime.getRuntime();
272 | runtime.exec("input keyevent " + KeyEvent.KEYCODE_BACK);
273 | } catch (IOException e) {
274 |
275 | }
276 | }
277 | }
278 | });
279 | fullButton = (ImageButton) mViewHolder.findViewById(R.id.play_full);
280 | fullButton.setOnClickListener(new Button.OnClickListener() {
281 | public void onClick(View v) {
282 | if (mVideoView != null) {
283 | fullScreen();
284 | }
285 | }
286 | });
287 | seekBar = (SeekBar) mViewHolder.findViewById(R.id.play_seekbar);
288 | seekBar.setMax(10000);//为了拖动的精确,设置最大为1w
289 | seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
290 | @Override
291 | public void onStopTrackingTouch(SeekBar seekBar) {
292 | isClick = false;
293 | int value = (int) Math.floor((double) allTime * ((double) seekBar.getProgress() / 10000));
294 | mVideoView.seekTo(value);
295 | }
296 |
297 | @Override
298 | public void onStartTrackingTouch(SeekBar seekBar) {
299 | isClick = true;
300 | delay = 5000;
301 | }
302 |
303 | @Override
304 | public void onProgressChanged(SeekBar seekBar, int progress,
305 | boolean fromUser) {
306 | }
307 | });
308 | mVideoView.setOnErrorListener(new IMediaPlayer.OnErrorListener() {
309 | @Override
310 | public boolean onError(IMediaPlayer iMediaPlayer, int i, int i1) {
311 | return mIjkEvent.onError(i);
312 | }
313 | });
314 |
315 | mVideoView.setOnCompletionListener(new IMediaPlayer.OnCompletionListener() {
316 | @Override
317 | public void onCompletion(IMediaPlayer iMediaPlayer) {
318 | playButton.setBackground(mVideoView.getResources().getDrawable(R.drawable.play_btn_play, null));
319 | }
320 | });
321 | mVideoView.setOnInfoListener(new IMediaPlayer.OnInfoListener() {
322 | @Override
323 | public boolean onInfo(IMediaPlayer iMediaPlayer, int i, int i1) {
324 | if (i == IMediaPlayer.MEDIA_INFO_AUDIO_RENDERING_START) {
325 | allTime = mVideoView.getDuration();
326 | Timer timer = new Timer();
327 | playAllTime.setText(timeLengthToTime(allTime));
328 | timer.schedule(new TimerTask() {
329 | public void run() {
330 | if (!isCreate) {
331 | cancel();
332 | return;
333 | }
334 | Message message = Message.obtain();
335 | message.arg1 = IMediaPlayer.MEDIA_INFO_AUDIO_RENDERING_START;
336 | mHandler.sendMessage(message);//发送消息
337 | }
338 | }, 1000, 1000);
339 | } else if (i == IMediaPlayer.MEDIA_INFO_BUFFERING_START) {
340 | mStatus.setVisibility(View.VISIBLE);
341 | loading();
342 | Rotation = 0;
343 | isLoading = true;
344 | } else if (i == IMediaPlayer.MEDIA_INFO_BUFFERING_END) {
345 | mStatus.setVisibility(View.GONE);
346 | isLoading = false;
347 | loadingView.setRotation(0);
348 | }
349 | return false;
350 | }
351 | });
352 | sharList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
353 | @Override
354 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
355 | selectShar(aptShar.getItem(position).getName());
356 | }
357 | });
358 | sharList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
359 | @Override
360 | public boolean onItemLongClick(AdapterView> parent, View view, int position, long id) {
361 | selectShar(aptShar.getItem(position).getName());
362 | return false;
363 | }
364 | });
365 |
366 | barLight.setProgress(getLight());
367 | AudioManager am = (AudioManager) ((Activity) mContext).getSystemService(Context.AUDIO_SERVICE);
368 | barSound.setMax(am.getStreamMaxVolume(AudioManager.STREAM_MUSIC));
369 | barSound.setProgress(am.getStreamVolume(AudioManager.STREAM_MUSIC));
370 | show();
371 | Rotation = 0;
372 |
373 | ((Activity) mContext).getApplication().registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
374 | public int mPlan;
375 |
376 | @Override
377 | public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
378 |
379 | }
380 |
381 | @Override
382 | public void onActivityStarted(Activity activity) {
383 | mPlan++;
384 | if (mPlan == 1) {
385 | mIjkEvent.onReception();
386 | }
387 | }
388 |
389 | @Override
390 | public void onActivityResumed(Activity activity) {
391 |
392 | }
393 |
394 | @Override
395 | public void onActivityPaused(Activity activity) {
396 |
397 | }
398 |
399 | @Override
400 | public void onActivityStopped(Activity activity) {
401 | mPlan--;
402 | if (mPlan == 0) {
403 | mIjkEvent.onBackstage();
404 | }
405 | }
406 |
407 | @Override
408 | public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
409 |
410 | }
411 |
412 | @Override
413 | public void onActivityDestroyed(Activity activity) {
414 |
415 | }
416 | });
417 | return playView;
418 | }
419 |
420 | public class shar {
421 | public String Name;
422 | public String Url;
423 |
424 | shar(String n, String u) {
425 | Name = n;
426 | Url = u;
427 | }
428 |
429 | @Override
430 | public String toString() {
431 | return Name;
432 | }
433 |
434 | public String getName() {
435 | return Name;
436 | }
437 |
438 | public String getUrl() {
439 | return Url;
440 | }
441 | }
442 |
443 | private ArrayAdapter aptShar;
444 |
445 | public void removeAllShar() {
446 | aptShar.clear();
447 | sharBtnLayout.setVisibility(View.GONE);
448 | }
449 |
450 | public void addShar(String Name, String Url) {
451 | if (sharBtnLayout.getVisibility() == View.GONE) {
452 | sharBtnLayout.setVisibility(View.VISIBLE);
453 | }
454 | aptShar.add(new shar(Name, Url));
455 | }
456 |
457 | private int sharSelectIndex = 0;
458 | shar tmpShar;
459 |
460 | public void selectShar(String Name) {
461 | sharLayout.setVisibility(View.GONE);
462 | for (int i = 0; i < aptShar.getCount(); i++) {
463 | tmpShar = aptShar.getItem(i);
464 | if (tmpShar.toString() == Name) {
465 | if (mIjkEvent == null) {
466 | sharSelectIndex = i;
467 | sharList.postDelayed(new Runnable() {
468 | @Override
469 | public void run() {
470 | int nowTime = mVideoView.getCurrentPosition();
471 | setVideoUrl(tmpShar.getUrl());
472 | seekTo(nowTime);
473 | start();
474 | sharBtn.setText(tmpShar.getName());
475 |
476 | sharList.requestFocusFromTouch();
477 | sharList.setSelection(sharSelectIndex);
478 | }
479 | }, 50);
480 |
481 | } else if (!mIjkEvent.onSharSwitch(tmpShar.getName(), tmpShar.getUrl())) {
482 | sharSelectIndex = i;
483 | sharList.postDelayed(new Runnable() {
484 | @Override
485 | public void run() {
486 | int nowTime = mVideoView.getCurrentPosition();
487 | setVideoUrl(tmpShar.getUrl());
488 | seekTo(nowTime);
489 | start();
490 | sharBtn.setText(tmpShar.getName());
491 |
492 | sharList.requestFocusFromTouch();
493 | sharList.setSelection(sharSelectIndex);
494 | }
495 | }, 50);
496 |
497 | }
498 | break;
499 | }
500 | }
501 | }
502 |
503 | private boolean isLoading = false;
504 | private int Rotation = 0;
505 |
506 | private void loading() {
507 | new Handler().postDelayed(new Runnable() {
508 | public void run() {
509 | if (isLoading) {
510 | loading();
511 | loadingView.setRotation(Rotation += 12);
512 | if (Rotation >= 360) Rotation -= 360;
513 | }
514 | }
515 | }, 50);
516 | }
517 |
518 | private int getLight() {
519 | Window window = ((Activity) mContext).getWindow();
520 | WindowManager.LayoutParams lp = window.getAttributes();
521 | if (lp.screenBrightness == -1) {
522 | return getScreenBrightness();
523 | }
524 | return (int) Math.floor(lp.screenBrightness * 255f);
525 | }
526 |
527 | public void setLight(int brightness) {
528 | Window window = ((Activity) mContext).getWindow();
529 | WindowManager.LayoutParams lp = window.getAttributes();
530 | if (brightness == -1) {
531 | lp.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
532 | } else {
533 | lp.screenBrightness = (brightness <= 0 ? 1 : brightness) / 255f;
534 | }
535 | window.setAttributes(lp);
536 | }
537 |
538 | private int getScreenBrightness() {
539 | ContentResolver contentResolver = ((Activity) mContext).getContentResolver();
540 | int defVal = 125;
541 | return Settings.System.getInt(contentResolver,
542 | Settings.System.SCREEN_BRIGHTNESS, defVal);
543 | }
544 |
545 | private boolean isCreate = false;
546 |
547 | public void deletePlayer() {
548 | isCreate = false;
549 | mVideoView.release(true);
550 | mViewHolder.removeAllViews();
551 | }
552 |
553 | public boolean isFull = false;
554 | IVideoEvent mIjkEvent;
555 |
556 | public void setEvent(IVideoEvent ev) {
557 | mIjkEvent = ev;
558 | }
559 |
560 | public void fullScreen() {
561 | //mIev.onFullScreen();
562 | if (isFull) {
563 | WindowManager.LayoutParams attr = ((Activity) mContext).getWindow().getAttributes();
564 | attr.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN);
565 | ((Activity) mContext).getWindow().setAttributes(attr);
566 | ((Activity) mContext).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
567 | showNavigation();
568 | if (((Activity) mContext).getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
569 | ((Activity) mContext).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
570 | }
571 | move(mLeft, mTop, mWidth, mHeight);
572 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
573 | fullButton.setBackground(mVideoView.getResources().getDrawable(R.drawable.play_btn_full, null));
574 | }
575 | isFull = false;
576 | } else {
577 | WindowManager.LayoutParams params = ((Activity) mContext).getWindow().getAttributes();
578 | params.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
579 | ((Activity) mContext).getWindow().setAttributes(params);
580 | ((Activity) mContext).getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
581 | hiddenNavigation();
582 | if (((Activity) mContext).getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
583 | ((Activity) mContext).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
584 | }
585 | move(0, 0, -1, -1);
586 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
587 | fullButton.setBackground(mVideoView.getResources().getDrawable(R.drawable.play_btn_full, null));
588 | }
589 | isFull = true;
590 | }
591 | show();
592 | }
593 |
594 | //隐藏虚拟按键
595 | private void hiddenNavigation() {
596 | int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
597 | ((Activity) mContext).getWindow().getDecorView().setSystemUiVisibility(uiOptions);
598 | }
599 |
600 | private void showNavigation() {
601 | int uiOptions = View.SYSTEM_UI_FLAG_VISIBLE;
602 | ((Activity) mContext).getWindow().getDecorView().setSystemUiVisibility(uiOptions);
603 | }
604 |
605 | public void move(int left, int top, int width, int height) {
606 | FrameLayout.LayoutParams rllp = (FrameLayout.LayoutParams) mViewHolder.getLayoutParams();
607 | rllp.width = width;
608 | rllp.height = height;
609 | rllp.leftMargin = left;
610 | rllp.topMargin = top;
611 | mViewHolder.setLayoutParams(rllp);
612 | }
613 |
614 | public boolean isPlaying() {
615 | return mVideoView.isPlaying();
616 | }
617 |
618 | public void pause() {
619 | mVideoView.pause();
620 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
621 | playButton.setBackground(mVideoView.getResources().getDrawable(R.drawable.play_btn_play, null));
622 | }
623 | }
624 |
625 | public void stop() {
626 | mVideoView.stopPlayback();
627 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
628 | playButton.setBackground(mVideoView.getResources().getDrawable(R.drawable.play_btn_play, null));
629 | }
630 | }
631 |
632 | public int getVideoTime() {
633 | return allTime;
634 | }
635 |
636 | private int allTime;
637 | private Handler mHandler = new Handler() {
638 | public void handleMessage(android.os.Message msg) {
639 | switch (msg.arg1) {
640 | case IMediaPlayer.MEDIA_INFO_AUDIO_RENDERING_START: {
641 | int nowTime = mVideoView.getCurrentPosition();
642 | seekBar.setSecondaryProgress(mVideoView.getBufferPercentage() * 100);
643 | if (!mGesture.isScroll && mGesture.Touch != myGestureListener.TOUCH_X) {
644 | playTime.setText(timeLengthToTime(nowTime));
645 | int value = (int) Math.floor(((double) nowTime / (double) allTime) * 10000);
646 | seekBar.setProgress(value);
647 | }
648 | break;
649 | }
650 | }
651 |
652 | }
653 | };
654 |
655 | private String timeLengthToTime(int length) {
656 | String retStr = new String();
657 | length /= 1000;
658 | int tmp = (int) Math.floor(length / 3600);
659 | length %= 3600;
660 | if (tmp > 0) {
661 | retStr = int2str(tmp) + ":";
662 | }
663 | tmp = (int) Math.floor(length / 60);
664 | length %= 60;
665 | retStr += int2str(tmp) + ":" + int2str(length);
666 | return retStr;
667 | }
668 |
669 | private String int2str(int value) {
670 | String ret = String.valueOf(value);
671 | while (ret.length() < 2) {
672 | ret = "0" + ret;
673 | }
674 | return ret;
675 | }
676 |
677 | class myGestureListener extends GestureDetector.SimpleOnGestureListener {
678 | public myGestureListener() {
679 | super();
680 | }
681 |
682 | private boolean isScroll = false;
683 | private int nowTime = 0;
684 |
685 | @Override
686 | public boolean onDown(MotionEvent event) {//手指按下
687 | if (isShowing()) {
688 | isClick = true;
689 | delay = 5000;
690 | }
691 | if (sharLayout.getVisibility() == View.VISIBLE) {
692 | sharLayout.setVisibility(View.GONE);
693 | }
694 | return true;
695 | }
696 |
697 | public static final int TOUCH_NULL = -1;//啥都没
698 | public static final int TOUCH_X = 0;//手指横向滑动
699 | public static final int TOUCH_LEFT_Y = 1;//手指左边纵向滑动
700 | public static final int TOUCH_RIGHT_Y = 2;//手指右边纵向滑动
701 | public int Touch = TOUCH_NULL;
702 | private int Progress = 0;//记录初始进度
703 | private int delay = 0;
704 |
705 | private void sleepHide(final View v) {
706 | new Handler().postDelayed(new Runnable() {
707 | public void run() {
708 | if (delay > 0) {
709 | if (Touch != TOUCH_NULL) {
710 | delay = 2000;
711 | } else {
712 | delay -= 1000;
713 | }
714 | sleepHide(v);
715 | } else {
716 | v.setVisibility(View.GONE);
717 | }
718 | }
719 | }, 1000);
720 | }
721 |
722 | @Override
723 | public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {//手指在触摸屏上滑动
724 | if (Touch == TOUCH_NULL) {
725 | Touch = getTouch(e1.getX(), e1.getY(), e2.getX(), e2.getY());
726 | isClick = true;
727 | isScroll = true;
728 | if (Touch == TOUCH_X) {
729 | Progress = seekBar.getProgress();
730 | nowTime = mVideoView.getCurrentPosition();
731 | } else if (Touch == TOUCH_LEFT_Y) {
732 | Progress = barLight.getProgress();
733 | mViewLight.setVisibility(View.VISIBLE);
734 | delay = 2000;
735 | sleepHide(mViewLight);
736 | } else if (Touch == TOUCH_RIGHT_Y) {
737 | AudioManager am = (AudioManager) ((Activity) mContext).getSystemService(Context.AUDIO_SERVICE);
738 | barSound.setProgress(am.getStreamVolume(AudioManager.STREAM_MUSIC));
739 | Progress = barSound.getProgress();
740 | mViewSound.setVisibility(View.VISIBLE);
741 | delay = 2000;
742 | sleepHide(mViewSound);
743 | }
744 | } else if (Touch == TOUCH_X) {
745 | //从左到右滚一次90秒
746 | ViewGroup.LayoutParams rllp = mViewHolder.getLayoutParams();
747 | float time = (90 / (float) getWidth()) * (e1.getX() - e2.getX());
748 | int x = (int) Math.floor(time * (10000 / (allTime / 1000)));
749 | seekBar.setProgress((int) (Progress - (int) (x)));
750 | playTime.setText(timeLengthToTime((int) Math.floor((float) nowTime - time * 1000)));//计算时间
751 | } else if (Touch == TOUCH_LEFT_Y) {
752 | float x = (127.5f / (float) getHeight()) * (e1.getY() - e2.getY());
753 | barLight.setProgress((int) (Progress + (int) Math.floor(x)));
754 | setLight(Progress + (int) Math.floor(x));
755 | } else if (Touch == TOUCH_RIGHT_Y) {
756 | AudioManager am = (AudioManager) ((Activity) mContext).getSystemService(Context.AUDIO_SERVICE);
757 | float x = (am.getStreamMaxVolume(AudioManager.STREAM_MUSIC) / 2 / (float) getHeight()) * (e1.getY() - e2.getY());
758 | barSound.setProgress((int) (Progress + (int) Math.floor(x)));
759 | am.setStreamVolume(AudioManager.STREAM_MUSIC, (int) (Progress + (int) Math.floor(x)), AudioManager.FLAG_PLAY_SOUND);
760 | }
761 | return true;
762 | }
763 |
764 | private int getWidth() {
765 | ViewGroup.LayoutParams rllp = mViewHolder.getLayoutParams();
766 | if (rllp.width == -1) {
767 | Resources resources = mViewHolder.getResources();
768 | DisplayMetrics dm = resources.getDisplayMetrics();
769 | return dm.widthPixels;
770 | }
771 | return rllp.width;
772 | }
773 |
774 | private int getHeight() {
775 | ViewGroup.LayoutParams rllp = mViewHolder.getLayoutParams();
776 | if (rllp.height == -1) {
777 | Resources resources = mViewHolder.getResources();
778 | DisplayMetrics dm = resources.getDisplayMetrics();
779 | return dm.heightPixels;
780 | }
781 | return rllp.height;
782 | }
783 |
784 | private int getTouch(float x, float y, float lx, float ly) {
785 | if (Math.abs(y - ly) < 20) {//判断y,绝对值小于20则认为是横向滑动
786 | return TOUCH_X;
787 | } else if (Math.abs(y - ly) > 20) {
788 | Resources resources = mContext.getResources();
789 | DisplayMetrics dm = resources.getDisplayMetrics();
790 | if ((dm.widthPixels / 2) > x) {
791 | return TOUCH_LEFT_Y;
792 | }
793 | return TOUCH_RIGHT_Y;
794 | }
795 | return TOUCH_NULL;
796 | }
797 |
798 | @Override
799 | public boolean onSingleTapUp(MotionEvent e) {//手指抬起
800 | Log.e(TAG, "手指抬起");
801 | isClick = false;
802 | isScroll = false;
803 | if (Touch != TOUCH_NULL) {
804 | if (Touch == TOUCH_X) {
805 | int value = (int) Math.floor((double) allTime * ((double) seekBar.getProgress() / 10000));
806 | mVideoView.seekTo(value);
807 | }
808 | }
809 | Touch = TOUCH_NULL;
810 | return true;
811 | }
812 |
813 | @Override
814 | public boolean onDoubleTap(MotionEvent e) {//双击
815 | if (isPlaying()) {
816 | pause();
817 | } else {
818 | start();
819 | }
820 | return true;
821 | }
822 |
823 | @Override
824 | public boolean onSingleTapConfirmed(MotionEvent e) {//单纯点击
825 | Log.e(TAG, "单纯点击");
826 | if (isShowing()) {
827 | hidden();
828 | Log.e(null, "隐藏");
829 | } else {
830 | show();
831 | Log.e(null, "显示");
832 | }
833 | return true;
834 | }
835 | }
836 |
837 | public boolean isShowing() {
838 | if (delay > 0) {
839 | return true;
840 | }
841 | return false;
842 | }
843 |
844 | private String playUrl = "";
845 | private boolean over = false;
846 |
847 | public void setVideoUrl(final String url) {
848 | playUrl = url;
849 | mVideoView.setHeaders(mHeaders);
850 | if (url.substring(url.length() - 3).indexOf("xml") >= 0) {
851 | over = false;
852 | new Thread() {
853 | @Override
854 | public void run() {
855 | try {
856 | URL tmp = new URL(url);
857 | HttpURLConnection connection = (HttpURLConnection) tmp.openConnection();
858 | connection.setRequestMethod("GET");
859 | connection.setDoInput(true);
860 | connection.setUseCaches(false);
861 | connection.setConnectTimeout(2000);
862 | connection.setReadTimeout(2000);
863 | //获得结果码
864 | connection.connect();
865 | int responseCode = connection.getResponseCode();
866 | if (responseCode == 200) {
867 | //请求成功 获得返回的流
868 | InputStream is = connection.getInputStream();
869 | InputStreamReader isr = new InputStreamReader(is);
870 | BufferedReader bufferReader = new BufferedReader(isr);
871 | String inputLine = "";
872 | String resultData = "";
873 | while ((inputLine = bufferReader.readLine()) != null) {
874 | resultData += inputLine + "\n";
875 | }
876 | if (resultData.length() >= 20) {
877 | playUrl = xml2ffconcat(resultData);
878 | }
879 |
880 | }
881 | } catch (MalformedURLException e) {
882 | e.printStackTrace();
883 | } catch (IOException e) {
884 | e.printStackTrace();
885 | }
886 | over = true;
887 | }
888 | }.start();
889 | while (!over) {
890 | try {
891 | Thread.sleep(100);
892 | } catch (InterruptedException e) {
893 |
894 | }
895 | }
896 | mVideoView.setVideoPath(playUrl);
897 | } else {
898 | mVideoView.setVideoPath(url);
899 | }
900 | }
901 |
902 | public void clearHeader() {
903 | mHeaders.clear();
904 | }
905 |
906 | public void addHeader(String key, String value) {
907 | mHeaders.put(key, value);
908 | }
909 |
910 | public String xml2ffconcat(String xmlText) {
911 | String cachePath = mContext.getCacheDir().getPath() + "/" + System.currentTimeMillis() + ".cae";
912 | try {
913 | File ffconcatCacheFile = new File(cachePath);
914 | if (!ffconcatCacheFile.exists()) {
915 | ffconcatCacheFile.createNewFile();
916 | }
917 | FileOutputStream bos = new FileOutputStream(ffconcatCacheFile);
918 | Pattern p = Pattern.compile("(.*?)");
919 | Matcher m = p.matcher(xmlText);
920 | String tmp = "ffconcat version 1.0\n";
921 | bos.write(("ffconcat version 1.0\n").getBytes("UTF-8"));
922 | while (m.find()) {
923 | tmp += "file '" + m.group(1) + "'\nduration " + m.group(2) + "\n";
924 | bos.write(("file '" + m.group(1) + "'\nduration " + m.group(2) + "\n").getBytes("UTF-8"));
925 | }
926 | } catch (Exception e) {
927 | e.printStackTrace();
928 | }
929 | return cachePath;
930 | }
931 |
932 | public void seekTo(int msec) {
933 | mVideoView.seekTo(msec);
934 | }
935 |
936 | public void start() {
937 | mStatus.setVisibility(View.GONE);
938 |
939 | mVideoView.start();
940 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
941 | playButton.setBackground(mVideoView.getResources().getDrawable(R.drawable.play_btn_pause, null));
942 | }
943 | }
944 |
945 | public int toggleAspectRatio(int aspect_ratio) {
946 | return mVideoView.toggleAspectRatio(aspect_ratio);
947 | }
948 |
949 | public void hidden() {
950 | delay = 0;
951 | mPlayTop.setVisibility(View.GONE);
952 | mPlayController.setVisibility(View.GONE);
953 | //全屏隐藏虚拟按键
954 | if (isFull) {
955 | hiddenNavigation();
956 | }
957 | }
958 |
959 | private int delay = 0;
960 | private boolean isClick = false;
961 |
962 | public void show() {
963 | show(5000);
964 | }
965 |
966 | public void show(int time) {
967 | if(!isAllShow){
968 | return;
969 | }
970 | if (isFull) {
971 | showNavigation();
972 | }
973 | // ((Activity)mContext).Pos();
974 | mPlayTop.setVisibility(View.VISIBLE);
975 | mPlayController.setVisibility(View.VISIBLE);
976 | mViewHolder.postInvalidate();
977 | mPlayTop.postInvalidate();
978 | mPlayController.postInvalidate();
979 | if (delay >= 0) {
980 | if (delay == 0) {
981 | delay = time;
982 | sleepHide();
983 | } else {
984 | delay = time;
985 | }
986 | }
987 | }
988 |
989 | private void sleepHide() {
990 | new Handler().postDelayed(new Runnable() {
991 | public void run() {
992 | if (delay > 0) {
993 | if (isClick) {
994 | delay = 5000;
995 | } else {
996 | delay -= 1000;
997 | }
998 | sleepHide();
999 | } else {
1000 | hidden();
1001 | }
1002 | }
1003 | }, 1000);
1004 | }
1005 | }
1006 |
--------------------------------------------------------------------------------