Commit ac138b3a03d56826adabc3f75241a5370514ad81

Authored by 王琳
0 parents

新建播放SDK demo

Showing 62 changed files with 3610 additions and 0 deletions
.gitignore 0 → 100644
  1 +++ a/.gitignore
  1 +*.iml
  2 +.gradle
  3 +/local.properties
  4 +/.idea/workspace.xml
  5 +/.idea/libraries
  6 +.DS_Store
  7 +/build
  8 +/captures
  9 +.externalNativeBuild
.idea/compiler.xml 0 → 100644
  1 +++ a/.idea/compiler.xml
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project version="4">
  3 + <component name="CompilerConfiguration">
  4 + <resourceExtensions />
  5 + <wildcardResourcePatterns>
  6 + <entry name="!?*.java" />
  7 + <entry name="!?*.form" />
  8 + <entry name="!?*.class" />
  9 + <entry name="!?*.groovy" />
  10 + <entry name="!?*.scala" />
  11 + <entry name="!?*.flex" />
  12 + <entry name="!?*.kt" />
  13 + <entry name="!?*.clj" />
  14 + <entry name="!?*.aj" />
  15 + </wildcardResourcePatterns>
  16 + <annotationProcessing>
  17 + <profile default="true" name="Default" enabled="false">
  18 + <processorPath useClasspath="true" />
  19 + </profile>
  20 + </annotationProcessing>
  21 + </component>
  22 +</project>
0 \ No newline at end of file 23 \ No newline at end of file
.idea/copyright/profiles_settings.xml 0 → 100644
  1 +++ a/.idea/copyright/profiles_settings.xml
  1 +<component name="CopyrightManager">
  2 + <settings default="" />
  3 +</component>
0 \ No newline at end of file 4 \ No newline at end of file
.idea/gradle.xml 0 → 100644
  1 +++ a/.idea/gradle.xml
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project version="4">
  3 + <component name="GradleSettings">
  4 + <option name="linkedExternalProjectsSettings">
  5 + <GradleProjectSettings>
  6 + <option name="distributionType" value="LOCAL" />
  7 + <option name="externalProjectPath" value="$PROJECT_DIR$" />
  8 + <option name="gradleHome" value="C:\Program Files\Android\Android Studio\gradle\gradle-2.14.1" />
  9 + <option name="modules">
  10 + <set>
  11 + <option value="$PROJECT_DIR$" />
  12 + <option value="$PROJECT_DIR$/app" />
  13 + </set>
  14 + </option>
  15 + <option name="resolveModulePerSourceSet" value="false" />
  16 + </GradleProjectSettings>
  17 + </option>
  18 + </component>
  19 +</project>
0 \ No newline at end of file 20 \ No newline at end of file
.idea/misc.xml 0 → 100644
  1 +++ a/.idea/misc.xml
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project version="4">
  3 + <component name="EntryPointsManager">
  4 + <entry_points version="2.0" />
  5 + </component>
  6 + <component name="NullableNotNullManager">
  7 + <option name="myDefaultNullable" value="android.support.annotation.Nullable" />
  8 + <option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
  9 + <option name="myNullables">
  10 + <value>
  11 + <list size="4">
  12 + <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
  13 + <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
  14 + <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
  15 + <item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
  16 + </list>
  17 + </value>
  18 + </option>
  19 + <option name="myNotNulls">
  20 + <value>
  21 + <list size="4">
  22 + <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
  23 + <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
  24 + <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
  25 + <item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
  26 + </list>
  27 + </value>
  28 + </option>
  29 + </component>
  30 + <component name="ProjectLevelVcsManager" settingsEditedManually="false">
  31 + <OptionsSetting value="true" id="Add" />
  32 + <OptionsSetting value="true" id="Remove" />
  33 + <OptionsSetting value="true" id="Checkout" />
  34 + <OptionsSetting value="true" id="Update" />
  35 + <OptionsSetting value="true" id="Status" />
  36 + <OptionsSetting value="true" id="Edit" />
  37 + <ConfirmationsSetting value="0" id="Add" />
  38 + <ConfirmationsSetting value="0" id="Remove" />
  39 + </component>
  40 + <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
  41 + <output url="file://$PROJECT_DIR$/build/classes" />
  42 + </component>
  43 + <component name="ProjectType">
  44 + <option name="id" value="Android" />
  45 + </component>
  46 +</project>
0 \ No newline at end of file 47 \ No newline at end of file
.idea/modules.xml 0 → 100644
  1 +++ a/.idea/modules.xml
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project version="4">
  3 + <component name="ProjectModuleManager">
  4 + <modules>
  5 + <module fileurl="file://$PROJECT_DIR$/QNVideoDemo.iml" filepath="$PROJECT_DIR$/QNVideoDemo.iml" />
  6 + <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
  7 + </modules>
  8 + </component>
  9 +</project>
0 \ No newline at end of file 10 \ No newline at end of file
.idea/runConfigurations.xml 0 → 100644
  1 +++ a/.idea/runConfigurations.xml
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project version="4">
  3 + <component name="RunConfigurationProducerService">
  4 + <option name="ignoredProducers">
  5 + <set>
  6 + <option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
  7 + <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
  8 + <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
  9 + </set>
  10 + </option>
  11 + </component>
  12 +</project>
0 \ No newline at end of file 13 \ No newline at end of file
.idea/vcs.xml 0 → 100644
  1 +++ a/.idea/vcs.xml
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project version="4">
  3 + <component name="VcsDirectoryMappings">
  4 + <mapping directory="$PROJECT_DIR$" vcs="Git" />
  5 + </component>
  6 +</project>
0 \ No newline at end of file 7 \ No newline at end of file
app/.gitignore 0 → 100644
  1 +++ a/app/.gitignore
  1 +/build
app/build.gradle 0 → 100644
  1 +++ a/app/build.gradle
  1 +apply plugin: 'com.android.application'
  2 +
  3 +android {
  4 + compileSdkVersion 24
  5 + buildToolsVersion "24.0.3"
  6 + defaultConfig {
  7 + applicationId "com.cnlive.demo.video"
  8 + minSdkVersion 16
  9 + targetSdkVersion 24
  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 +}
  21 +
  22 +dependencies {
  23 + compile fileTree(include: ['*.jar'], dir: 'libs')
  24 + androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
  25 + exclude group: 'com.android.support', module: 'support-annotations'
  26 + })
  27 + compile 'com.android.support:appcompat-v7:24.2.1'
  28 + testCompile 'junit:junit:4.12'
  29 + compile files('libs/libcnlivevideo.jar')
  30 + compile files('libs/libcnliveutilplus.jar')
  31 +}
app/libs/libcnliveutilplus.jar 0 → 100644
No preview for this file type
app/libs/libcnlivevideo.jar 0 → 100644
No preview for this file type
app/proguard-rules.pro 0 → 100644
  1 +++ a/app/proguard-rules.pro
  1 +# Add project specific ProGuard rules here.
  2 +# By default, the flags in this file are appended to flags specified
  3 +# in D:\android_sdk/tools/proguard/proguard-android.txt
  4 +# You can edit the include path and order by changing the proguardFiles
  5 +# directive in build.gradle.
  6 +#
  7 +# For more details, see
  8 +# http://developer.android.com/guide/developing/tools/proguard.html
  9 +
  10 +# Add any project specific keep options here:
  11 +
  12 +# If your project uses WebView with JS, uncomment the following
  13 +# and specify the fully qualified class name to the JavaScript interface
  14 +# class:
  15 +#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
  16 +# public *;
  17 +#}
app/src/androidTest/java/com/cnlive/demo/video/ExampleInstrumentedTest.java 0 → 100644
  1 +++ a/app/src/androidTest/java/com/cnlive/demo/video/ExampleInstrumentedTest.java
  1 +package com.cnlive.demo.video;
  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 <a href="http://d.android.com/tools/testing">Testing documentation</a>
  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.cnlive.demo.video", appContext.getPackageName());
  25 + }
  26 +}
app/src/main/AndroidManifest.xml 0 → 100644
  1 +++ a/app/src/main/AndroidManifest.xml
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3 + package="com.cnlive.demo.video">
  4 +
  5 + <uses-permission android:name="android.permission.INTERNET" />
  6 + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  7 + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  8 + <uses-permission android:name="android.permission.WAKE_LOCK" />
  9 + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  10 +
  11 + <application
  12 + android:name=".VideoApplication"
  13 + android:allowBackup="true"
  14 + android:icon="@mipmap/ic_launcher"
  15 + android:label="@string/app_name"
  16 + android:supportsRtl="true"
  17 + android:theme="@style/AppTheme">
  18 + <activity android:name=".MainActivity">
  19 + <intent-filter>
  20 + <action android:name="android.intent.action.MAIN" />
  21 +
  22 + <category android:name="android.intent.category.LAUNCHER" />
  23 + </intent-filter>
  24 + </activity>
  25 + <activity android:name=".CNMediaPlayerActivity" />
  26 + <activity android:name=".CNAudioPlayerActivity" />
  27 + <activity android:name=".CNVideoViewActivity" />
  28 + <activity android:name=".CNVideoTextureActivity" />
  29 + <activity android:name=".VideoViewActivity" />
  30 + <activity android:name=".VideoFileActivity" />
  31 + </application>
  32 +
  33 +</manifest>
0 \ No newline at end of file 34 \ No newline at end of file
app/src/main/java/com/cnlive/demo/video/CNAudioPlayerActivity.java 0 → 100644
  1 +++ a/app/src/main/java/com/cnlive/demo/video/CNAudioPlayerActivity.java
  1 +package com.cnlive.demo.video;
  2 +
  3 +import android.content.Context;
  4 +import android.media.AudioManager;
  5 +import android.os.Bundle;
  6 +import android.os.Handler;
  7 +import android.os.Looper;
  8 +import android.os.Message;
  9 +import android.os.PowerManager;
  10 +import android.support.v7.app.AppCompatActivity;
  11 +import android.util.Log;
  12 +import android.view.View;
  13 +import android.widget.Toast;
  14 +
  15 +import com.cnlive.demo.video.utils.Utils;
  16 +import com.cnlive.libs.lib_cnvideo.base.IAVOptions;
  17 +import com.cnlive.libs.lib_cnvideo.base.IMediaPlayer;
  18 +import com.cnlive.libs.lib_cnvideo.player.AVOptions;
  19 +import com.cnlive.libs.lib_cnvideo.player.MediaPlayer;
  20 +
  21 +import java.io.IOException;
  22 +
  23 +/**
  24 + * This demo shows how to use PLMediaPlayer API playing audio stream
  25 + */
  26 +public class CNAudioPlayerActivity extends AppCompatActivity {
  27 +
  28 + private static final String TAG = CNAudioPlayerActivity.class.getSimpleName();
  29 +
  30 + private static final int MESSAGE_ID_RECONNECTING = 0x01;
  31 +
  32 + private MediaPlayer mMediaPlayer;
  33 + private String mAudioPath;
  34 + private View mLoadingView;
  35 + private AVOptions mAVOptions;
  36 + private boolean mIsStopped = false;
  37 + private boolean mIsActivityPaused = true;
  38 + private Toast mToast = null;
  39 +
  40 + @Override
  41 + protected void onCreate(Bundle savedInstanceState) {
  42 + super.onCreate(savedInstanceState);
  43 + setContentView(R.layout.activity_audio_player);
  44 + mLoadingView = findViewById(R.id.LoadingView);
  45 + mAudioPath = getIntent().getStringExtra("videoPath");
  46 +
  47 + //配置播放参数
  48 + mAVOptions = new AVOptions();
  49 +
  50 + int isLiveStreaming = getIntent().getIntExtra("liveStreaming", 1);
  51 + //
  52 + mAVOptions.setInteger(IAVOptions.KEY_PREPARE_TIMEOUT, 10 * 1000);
  53 + mAVOptions.setInteger(IAVOptions.KEY_GET_AV_FRAME_TIMEOUT, 10 * 1000);
  54 + // Some optimization with buffering mechanism when be set to 1
  55 + mAVOptions.setInteger(IAVOptions.KEY_LIVE_STREAMING, isLiveStreaming);
  56 + if (isLiveStreaming == 1) {
  57 + mAVOptions.setInteger(IAVOptions.KEY_DELAY_OPTIMIZATION, 1);
  58 + }
  59 +
  60 + // 1 -> hw codec enable, 0 -> disable [recommended]
  61 + int codec = getIntent().getIntExtra("mediaCodec", 0);
  62 + mAVOptions.setInteger(IAVOptions.KEY_MEDIACODEC, codec);
  63 +
  64 + // whether start play automatically after prepared, default value is 1
  65 + mAVOptions.setInteger(IAVOptions.KEY_START_ON_PREPARED, 0);
  66 +
  67 + AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
  68 + audioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
  69 +
  70 + prepare();
  71 + }
  72 +
  73 + @Override
  74 + protected void onDestroy() {
  75 + super.onDestroy();
  76 + release();
  77 + AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
  78 + audioManager.abandonAudioFocus(null);
  79 + }
  80 +
  81 + @Override
  82 + protected void onResume() {
  83 + super.onResume();
  84 + mIsActivityPaused = false;
  85 + // mMediaPlayer.start();
  86 + }
  87 +
  88 + @Override
  89 + protected void onPause() {
  90 + super.onPause();
  91 + mIsActivityPaused = true;
  92 + // mMediaPlayer.pause();
  93 + }
  94 +
  95 + public void onClickPlay(View v) {
  96 + if (mIsStopped) {
  97 + prepare();
  98 + } else {
  99 + mMediaPlayer.start();
  100 + }
  101 + }
  102 +
  103 + public void onClickPause(View v) {
  104 + if (mMediaPlayer != null) {
  105 + mMediaPlayer.pause();
  106 + }
  107 + }
  108 +
  109 + public void onClickResume(View v) {
  110 + if (mMediaPlayer != null) {
  111 + mMediaPlayer.start();
  112 + }
  113 + }
  114 +
  115 + public void onClickStop(View v) {
  116 + if (mMediaPlayer != null) {
  117 + mMediaPlayer.stop();
  118 + mMediaPlayer.reset();
  119 + }
  120 + mIsStopped = true;
  121 + mMediaPlayer = null;
  122 + }
  123 +
  124 + public void release() {
  125 + if (mMediaPlayer != null) {
  126 + mMediaPlayer.stop();
  127 + mMediaPlayer.release();
  128 + mMediaPlayer = null;
  129 + }
  130 + }
  131 +
  132 + private void prepare() {
  133 + if (mMediaPlayer == null) {
  134 + mMediaPlayer = new MediaPlayer(getApplicationContext(), mAVOptions);
  135 + mMediaPlayer.setOnPreparedListener(mOnPreparedListener);
  136 + mMediaPlayer.setOnCompletionListener(mOnCompletionListener);
  137 + mMediaPlayer.setOnErrorListener(mOnErrorListener);
  138 + mMediaPlayer.setOnInfoListener(mOnInfoListener);
  139 + mMediaPlayer.setOnBufferingUpdateListener(mOnBufferingUpdateListener);
  140 + mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
  141 + }
  142 + try {
  143 + mMediaPlayer.setDataSource(mAudioPath);
  144 + mMediaPlayer.prepareAsync();
  145 + } catch (IllegalArgumentException e) {
  146 + e.printStackTrace();
  147 + } catch (IllegalStateException e) {
  148 + e.printStackTrace();
  149 + } catch (IOException e) {
  150 + e.printStackTrace();
  151 + }
  152 + }
  153 +
  154 + private IMediaPlayer.OnPreparedListener mOnPreparedListener = new IMediaPlayer.OnPreparedListener() {
  155 + @Override
  156 + public void onPrepared(IMediaPlayer mp) {
  157 + Log.i(TAG, "On Prepared !");
  158 + mMediaPlayer.start();
  159 + mIsStopped = false;
  160 + }
  161 + };
  162 +
  163 + private IMediaPlayer.OnInfoListener mOnInfoListener = new IMediaPlayer.OnInfoListener() {
  164 + @Override
  165 + public boolean onInfo(IMediaPlayer mp, int what, int extra) {
  166 + Log.i(TAG, "OnInfo, what = " + what + ", extra = " + extra);
  167 + switch (what) {
  168 + case IMediaPlayer.MEDIA_INFO_BUFFERING_START:
  169 + mLoadingView.setVisibility(View.VISIBLE);
  170 + break;
  171 + case IMediaPlayer.MEDIA_INFO_BUFFERING_END:
  172 + case IMediaPlayer.MEDIA_INFO_AUDIO_RENDERING_START:
  173 + mLoadingView.setVisibility(View.GONE);
  174 + break;
  175 + default:
  176 + break;
  177 + }
  178 + return true;
  179 + }
  180 + };
  181 +
  182 + private IMediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener = new IMediaPlayer.OnBufferingUpdateListener() {
  183 + @Override
  184 + public void onBufferingUpdate(IMediaPlayer mp, int percent) {
  185 + Log.d(TAG, "onBufferingUpdate: " + percent + "%");
  186 + }
  187 + };
  188 +
  189 + /**
  190 + * Listen the event of playing complete
  191 + * For playing local file, it's called when reading the file EOF
  192 + * For playing network stream, it's called when the buffered bytes played over
  193 + *
  194 + * If setLooping(true) is called, the player will restart automatically
  195 + * And `onCompletion` will not be called
  196 + */
  197 + private IMediaPlayer.OnCompletionListener mOnCompletionListener = new IMediaPlayer.OnCompletionListener() {
  198 + @Override
  199 + public void onCompletion(IMediaPlayer mp) {
  200 + Log.d(TAG, "Play Completed !");
  201 + }
  202 + };
  203 +
  204 + private IMediaPlayer.OnErrorListener mOnErrorListener = new IMediaPlayer.OnErrorListener() {
  205 + @Override
  206 + public boolean onError(IMediaPlayer mp, int errorCode) {
  207 + boolean isNeedReconnect = false;
  208 + Log.e(TAG, "Error happened, errorCode = " + errorCode);
  209 + switch (errorCode) {
  210 + case IMediaPlayer.ERROR_CODE_INVALID_URI:
  211 + showToastTips("Invalid URL !");
  212 + break;
  213 + case IMediaPlayer.ERROR_CODE_404_NOT_FOUND:
  214 + showToastTips("404 resource not found !");
  215 + break;
  216 + case IMediaPlayer.ERROR_CODE_CONNECTION_REFUSED:
  217 + showToastTips("Connection refused !");
  218 + break;
  219 + case IMediaPlayer.ERROR_CODE_CONNECTION_TIMEOUT:
  220 + showToastTips("Connection timeout !");
  221 + isNeedReconnect = true;
  222 + break;
  223 + case IMediaPlayer.ERROR_CODE_EMPTY_PLAYLIST:
  224 + showToastTips("Empty playlist !");
  225 + break;
  226 + case IMediaPlayer.ERROR_CODE_STREAM_DISCONNECTED:
  227 + showToastTips("Stream disconnected !");
  228 + isNeedReconnect = true;
  229 + break;
  230 + case IMediaPlayer.ERROR_CODE_IO_ERROR:
  231 + showToastTips("Network IO Error !");
  232 + isNeedReconnect = true;
  233 + break;
  234 + case IMediaPlayer.ERROR_CODE_UNAUTHORIZED:
  235 + showToastTips("Unauthorized Error !");
  236 + break;
  237 + case IMediaPlayer.ERROR_CODE_PREPARE_TIMEOUT:
  238 + showToastTips("Prepare timeout !");
  239 + isNeedReconnect = true;
  240 + break;
  241 + case IMediaPlayer.ERROR_CODE_READ_FRAME_TIMEOUT:
  242 + showToastTips("Read frame timeout !");
  243 + isNeedReconnect = true;
  244 + break;
  245 + case IMediaPlayer.MEDIA_ERROR_UNKNOWN:
  246 + break;
  247 + default:
  248 + showToastTips("unknown error !");
  249 + break;
  250 + }
  251 + // Todo pls handle the error status here, reconnect or call finish()
  252 + release();
  253 + if (isNeedReconnect) {
  254 + sendReconnectMessage();
  255 + } else {
  256 + finish();
  257 + }
  258 + // Return true means the error has been handled
  259 + // If return false, then `onCompletion` will be called
  260 + return true;
  261 + }
  262 + };
  263 +
  264 + private void showToastTips(final String tips) {
  265 + if (mIsActivityPaused) {
  266 + return;
  267 + }
  268 + runOnUiThread(new Runnable() {
  269 + @Override
  270 + public void run() {
  271 + if (mToast != null) {
  272 + mToast.cancel();
  273 + }
  274 + mToast = Toast.makeText(CNAudioPlayerActivity.this, tips, Toast.LENGTH_SHORT);
  275 + mToast.show();
  276 + }
  277 + });
  278 + }
  279 +
  280 + private void sendReconnectMessage() {
  281 + showToastTips("正在重连...");
  282 + mLoadingView.setVisibility(View.VISIBLE);
  283 + mHandler.removeCallbacksAndMessages(null);
  284 + mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_ID_RECONNECTING), 500);
  285 + }
  286 +
  287 + protected Handler mHandler = new Handler(Looper.getMainLooper()) {
  288 + @Override
  289 + public void handleMessage(Message msg) {
  290 + if (msg.what != MESSAGE_ID_RECONNECTING) {
  291 + return;
  292 + }
  293 + if (mIsActivityPaused || !Utils.isLiveStreamingAvailable()) {
  294 + finish();
  295 + return;
  296 + }
  297 + if (!Utils.isNetworkAvailable(CNAudioPlayerActivity.this)) {
  298 + sendReconnectMessage();
  299 + return;
  300 + }
  301 + // The PLMediaPlayer has moved to the Error state, if you want to retry, must reset first !
  302 + prepare();
  303 + }
  304 + };
  305 +}
app/src/main/java/com/cnlive/demo/video/CNMediaPlayerActivity.java 0 → 100644
  1 +++ a/app/src/main/java/com/cnlive/demo/video/CNMediaPlayerActivity.java
  1 +package com.cnlive.demo.video;
  2 +
  3 +import android.content.Context;
  4 +import android.media.AudioManager;
  5 +import android.os.Bundle;
  6 +import android.os.Handler;
  7 +import android.os.Looper;
  8 +import android.os.Message;
  9 +import android.os.PowerManager;
  10 +import android.util.Log;
  11 +import android.view.Gravity;
  12 +import android.view.SurfaceHolder;
  13 +import android.view.SurfaceView;
  14 +import android.view.View;
  15 +import android.widget.FrameLayout;
  16 +import android.widget.Toast;
  17 +
  18 +import com.cnlive.demo.video.utils.Utils;
  19 +import com.cnlive.libs.lib_cnvideo.base.IAVOptions;
  20 +import com.cnlive.libs.lib_cnvideo.base.IDataSource;
  21 +import com.cnlive.libs.lib_cnvideo.base.IMediaPlayer;
  22 +import com.cnlive.libs.lib_cnvideo.player.AVOptions;
  23 +import com.cnlive.libs.lib_cnvideo.player.MediaPlayer;
  24 +import com.cnlive.libs.util.Config;
  25 +
  26 +import java.io.IOException;
  27 +
  28 +/**
  29 + * This demo shows how to use IMediaPlayer API playing video stream
  30 + */
  31 +public class CNMediaPlayerActivity extends VideoPlayerBaseActivity {
  32 +
  33 + private static final String TAG = CNMediaPlayerActivity.class.getSimpleName();
  34 +
  35 + private static final int MESSAGE_ID_RECONNECTING = 0x01;
  36 +
  37 + private SurfaceView mSurfaceView;
  38 + private MediaPlayer mMediaPlayer;
  39 + private View mLoadingView;
  40 + private AVOptions mAVOptions;
  41 +
  42 + private int mSurfaceWidth = 0;
  43 + private int mSurfaceHeight = 0;
  44 +
  45 + private String mVideoPath = null;
  46 + private boolean mIsStopped = false;
  47 + private boolean mIsActivityPaused = true;
  48 +
  49 + private Toast mToast = null;
  50 +
  51 + @Override
  52 + protected void onCreate(Bundle savedInstanceState) {
  53 + super.onCreate(savedInstanceState);
  54 + setContentView(R.layout.activity_media_player);
  55 + mLoadingView = findViewById(R.id.LoadingView);
  56 + mSurfaceView = (SurfaceView) findViewById(R.id.SurfaceView);
  57 + mSurfaceView.getHolder().addCallback(mCallback);
  58 +
  59 + mVideoPath = getIntent().getStringExtra("videoPath");
  60 +
  61 + mAVOptions = new AVOptions();
  62 +
  63 + int isLiveStreaming = getIntent().getIntExtra("liveStreaming", 1);
  64 + // the unit of timeout is ms
  65 + mAVOptions.setInteger(IAVOptions.KEY_PREPARE_TIMEOUT, 10 * 1000);
  66 + mAVOptions.setInteger(IAVOptions.KEY_GET_AV_FRAME_TIMEOUT, 10 * 1000);
  67 + // Some optimization with buffering mechanism when be set to 1
  68 + mAVOptions.setInteger(IAVOptions.KEY_LIVE_STREAMING, isLiveStreaming);
  69 + if (isLiveStreaming == 1) {
  70 + mAVOptions.setInteger(IAVOptions.KEY_DELAY_OPTIMIZATION, 1);
  71 + }
  72 +
  73 + // 1 -> hw codec enable, 0 -> disable [recommended]
  74 + int codec = getIntent().getIntExtra("mediaCodec", 0);
  75 + mAVOptions.setInteger(IAVOptions.KEY_MEDIACODEC, codec);
  76 +
  77 + // whether start play automatically after prepared, default value is 1
  78 + mAVOptions.setInteger(IAVOptions.KEY_START_ON_PREPARED, 0);
  79 +
  80 + AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
  81 + audioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
  82 + }
  83 +
  84 + @Override
  85 + protected void onDestroy() {
  86 + super.onDestroy();
  87 + release();
  88 + AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
  89 + audioManager.abandonAudioFocus(null);
  90 + }
  91 +
  92 + @Override
  93 + protected void onResume() {
  94 + super.onResume();
  95 + mIsActivityPaused = false;
  96 + }
  97 +
  98 + @Override
  99 + protected void onPause() {
  100 + super.onPause();
  101 + mIsActivityPaused = true;
  102 + }
  103 +
  104 + public void onClickPlay(View v) {
  105 + if (mIsStopped) {
  106 + prepare();
  107 + } else {
  108 + mMediaPlayer.start();
  109 + }
  110 + }
  111 +
  112 + public void onClickPause(View v) {
  113 + if (mMediaPlayer != null) {
  114 + mMediaPlayer.pause();
  115 + }
  116 + }
  117 +
  118 + public void onClickResume(View v) {
  119 + if (mMediaPlayer != null) {
  120 + mMediaPlayer.start();
  121 + }
  122 + }
  123 +
  124 + public void onClickStop(View v) {
  125 + if (mMediaPlayer != null) {
  126 + mMediaPlayer.stop();
  127 + mMediaPlayer.reset();
  128 + }
  129 + mIsStopped = true;
  130 + mMediaPlayer = null;
  131 + }
  132 +
  133 + public void releaseWithoutStop() {
  134 + if (mMediaPlayer != null) {
  135 + mMediaPlayer.setDisplay(null);
  136 + }
  137 + }
  138 +
  139 + public void release() {
  140 + if (mMediaPlayer != null) {
  141 + mMediaPlayer.stop();
  142 + mMediaPlayer.release();
  143 + mMediaPlayer = null;
  144 + }
  145 + }
  146 +
  147 + private void prepare() {
  148 +
  149 + if (mMediaPlayer != null) {
  150 + mMediaPlayer.setDisplay(mSurfaceView.getHolder());
  151 + return;
  152 + }
  153 +
  154 + try {
  155 + mMediaPlayer = new MediaPlayer(this, mAVOptions);
  156 +
  157 + mMediaPlayer.setOnPreparedListener(mOnPreparedListener);
  158 + mMediaPlayer.setOnVideoSizeChangedListener(mOnVideoSizeChangedListener);
  159 + mMediaPlayer.setOnCompletionListener(mOnCompletionListener);
  160 + mMediaPlayer.setOnErrorListener(mOnErrorListener);
  161 + mMediaPlayer.setOnInfoListener(mOnInfoListener);
  162 + mMediaPlayer.setOnBufferingUpdateListener(mOnBufferingUpdateListener);
  163 +
  164 + // set replay if completed
  165 + // mMediaPlayer.setLooping(true);
  166 +
  167 + mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
  168 +
  169 + mMediaPlayer.setDataSource(mVideoPath);
  170 + //播放视讯云视频
  171 +// mMediaPlayer.setDataSource(new IDataSource() {
  172 +// @Override
  173 +// public String getId() {
  174 +// return "qwert";
  175 +// }
  176 +//
  177 +// @Override
  178 +// public String getType() {
  179 +// return Config.TYPE_LIVE;
  180 +// }
  181 +//
  182 +// @Override
  183 +// public String getRate() {
  184 +// return null;
  185 +// }
  186 +// }, false);
  187 + mMediaPlayer.setDisplay(mSurfaceView.getHolder());
  188 + mMediaPlayer.prepareAsync();
  189 + } catch (UnsatisfiedLinkError e) {
  190 + e.printStackTrace();
  191 + } catch (IllegalArgumentException e) {
  192 + e.printStackTrace();
  193 + } catch (IllegalStateException e) {
  194 + e.printStackTrace();
  195 + }
  196 + catch (IOException e) {
  197 + e.printStackTrace();
  198 + }
  199 + }
  200 +
  201 + private SurfaceHolder.Callback mCallback = new SurfaceHolder.Callback() {
  202 +
  203 + @Override
  204 + public void surfaceCreated(SurfaceHolder holder) {
  205 + prepare();
  206 + }
  207 +
  208 + @Override
  209 + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  210 + mSurfaceWidth = width;
  211 + mSurfaceHeight = height;
  212 + }
  213 +
  214 + @Override
  215 + public void surfaceDestroyed(SurfaceHolder holder) {
  216 + // release();
  217 + releaseWithoutStop();
  218 + }
  219 + };
  220 +
  221 + private IMediaPlayer.OnVideoSizeChangedListener mOnVideoSizeChangedListener = new IMediaPlayer.OnVideoSizeChangedListener() {
  222 + public void onVideoSizeChanged(IMediaPlayer mp, int width, int height) {
  223 + Log.i(TAG, "onVideoSizeChanged, width = "+ width + ",height = " + height);
  224 + // resize the display window to fit the screen
  225 + if (width != 0 && height != 0) {
  226 + float ratioW = (float) width/(float) mSurfaceWidth;
  227 + float ratioH = (float) height/(float) mSurfaceHeight;
  228 + float ratio = Math.max(ratioW, ratioH);
  229 + width = (int) Math.ceil((float)width/ratio);
  230 + height = (int) Math.ceil((float)height/ratio);
  231 + FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(width, height);
  232 + layout.gravity = Gravity.CENTER;
  233 + mSurfaceView.setLayoutParams(layout);
  234 + }
  235 + }
  236 + };
  237 +
  238 + private IMediaPlayer.OnPreparedListener mOnPreparedListener = new IMediaPlayer.OnPreparedListener() {
  239 + @Override
  240 + public void onPrepared(IMediaPlayer mp) {
  241 + Log.i(TAG, "On Prepared !");
  242 + mMediaPlayer.start();
  243 + mIsStopped = false;
  244 + }
  245 + };
  246 +
  247 + private IMediaPlayer.OnInfoListener mOnInfoListener = new IMediaPlayer.OnInfoListener() {
  248 + @Override
  249 + public boolean onInfo(IMediaPlayer mp, int what, int extra) {
  250 + Log.i(TAG, "OnInfo, what = " + what + ", extra = " + extra);
  251 + switch (what) {
  252 + case IMediaPlayer.MEDIA_INFO_BUFFERING_START:
  253 + mLoadingView.setVisibility(View.VISIBLE);
  254 + break;
  255 + case IMediaPlayer.MEDIA_INFO_BUFFERING_END:
  256 + case IMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START:
  257 + mLoadingView.setVisibility(View.GONE);
  258 + break;
  259 + default:
  260 + break;
  261 + }
  262 + return true;
  263 + }
  264 + };
  265 +
  266 + private IMediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener = new IMediaPlayer.OnBufferingUpdateListener() {
  267 + @Override
  268 + public void onBufferingUpdate(IMediaPlayer mp, int percent) {
  269 + Log.d(TAG, "onBufferingUpdate: " + percent + "%");
  270 + }
  271 + };
  272 +
  273 + /**
  274 + * Listen the event of playing complete
  275 + * For playing local file, it's called when reading the file EOF
  276 + * For playing network stream, it's called when the buffered bytes played over
  277 + *
  278 + * If setLooping(true) is called, the player will restart automatically
  279 + * And `onCompletion` will not be called
  280 + *
  281 + */
  282 + private IMediaPlayer.OnCompletionListener mOnCompletionListener = new IMediaPlayer.OnCompletionListener() {
  283 + @Override
  284 + public void onCompletion(IMediaPlayer mp) {
  285 + Log.d(TAG, "Play Completed !");
  286 + showToastTips("Play Completed !");
  287 + finish();
  288 + }
  289 + };
  290 +
  291 + private IMediaPlayer.OnErrorListener mOnErrorListener = new IMediaPlayer.OnErrorListener() {
  292 + @Override
  293 + public boolean onError(IMediaPlayer mp, int errorCode) {
  294 + boolean isNeedReconnect = false;
  295 + Log.e(TAG, "Error happened, errorCode = " + errorCode);
  296 + switch (errorCode) {
  297 + case IMediaPlayer.ERROR_CODE_INVALID_URI:
  298 + showToastTips("Invalid URL !");
  299 + break;
  300 + case IMediaPlayer.ERROR_CODE_404_NOT_FOUND:
  301 + showToastTips("404 resource not found !");
  302 + break;
  303 + case IMediaPlayer.ERROR_CODE_CONNECTION_REFUSED:
  304 + showToastTips("Connection refused !");
  305 + break;
  306 + case IMediaPlayer.ERROR_CODE_CONNECTION_TIMEOUT:
  307 + showToastTips("Connection timeout !");
  308 + isNeedReconnect = true;
  309 + break;
  310 + case IMediaPlayer.ERROR_CODE_EMPTY_PLAYLIST:
  311 + showToastTips("Empty playlist !");
  312 + break;
  313 + case IMediaPlayer.ERROR_CODE_STREAM_DISCONNECTED:
  314 + showToastTips("Stream disconnected !");
  315 + isNeedReconnect = true;
  316 + break;
  317 + case IMediaPlayer.ERROR_CODE_IO_ERROR:
  318 + showToastTips("Network IO Error !");
  319 + isNeedReconnect = true;
  320 + break;
  321 + case IMediaPlayer.ERROR_CODE_UNAUTHORIZED:
  322 + showToastTips("Unauthorized Error !");
  323 + break;
  324 + case IMediaPlayer.ERROR_CODE_PREPARE_TIMEOUT:
  325 + showToastTips("Prepare timeout !");
  326 + isNeedReconnect = true;
  327 + break;
  328 + case IMediaPlayer.ERROR_CODE_READ_FRAME_TIMEOUT:
  329 + showToastTips("Read frame timeout !");
  330 + isNeedReconnect = true;
  331 + break;
  332 + case IMediaPlayer.MEDIA_ERROR_UNKNOWN:
  333 + break;
  334 + default:
  335 + showToastTips("unknown error !");
  336 + break;
  337 + }
  338 + // Todo pls handle the error status here, reconnect or call finish()
  339 +// release();
  340 +// if (isNeedReconnect) {
  341 +// sendReconnectMessage();
  342 +// } else {
  343 +// finish();
  344 +// }
  345 + // Return true means the error has been handled
  346 + // If return false, then `onCompletion` will be called
  347 + return true;
  348 + }
  349 + };
  350 +
  351 + private void showToastTips(final String tips) {
  352 + if (mIsActivityPaused) {
  353 + return;
  354 + }
  355 + runOnUiThread(new Runnable() {
  356 + @Override
  357 + public void run() {
  358 + if (mToast != null) {
  359 + mToast.cancel();
  360 + }
  361 + mToast = Toast.makeText(CNMediaPlayerActivity.this, tips, Toast.LENGTH_SHORT);
  362 + mToast.show();
  363 + }
  364 + });
  365 + }
  366 +
  367 + private void sendReconnectMessage() {
  368 + showToastTips("正在重连...");
  369 + mLoadingView.setVisibility(View.VISIBLE);
  370 + mHandler.removeCallbacksAndMessages(null);
  371 + mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_ID_RECONNECTING), 500);
  372 + }
  373 +
  374 + protected Handler mHandler = new Handler(Looper.getMainLooper()) {
  375 + @Override
  376 + public void handleMessage(Message msg) {
  377 + if (msg.what != MESSAGE_ID_RECONNECTING) {
  378 + return;
  379 + }
  380 + if (mIsActivityPaused || !Utils.isLiveStreamingAvailable()) {
  381 + finish();
  382 + return;
  383 + }
  384 + if (!Utils.isNetworkAvailable(CNMediaPlayerActivity.this)) {
  385 + sendReconnectMessage();
  386 + return;
  387 + }
  388 + prepare();
  389 + }
  390 + };
  391 +}
app/src/main/java/com/cnlive/demo/video/CNVideoTextureActivity.java 0 → 100644
  1 +++ a/app/src/main/java/com/cnlive/demo/video/CNVideoTextureActivity.java
  1 +package com.cnlive.demo.video;
  2 +
  3 +import android.os.Bundle;
  4 +import android.os.Handler;
  5 +import android.os.Looper;
  6 +import android.os.Message;
  7 +import android.view.View;
  8 +import android.widget.ImageView;
  9 +import android.widget.Toast;
  10 +
  11 +import com.cnlive.demo.video.utils.Utils;
  12 +import com.cnlive.demo.video.widget.MediaController;
  13 +import com.cnlive.libs.lib_cnvideo.base.IAVOptions;
  14 +import com.cnlive.libs.lib_cnvideo.base.ICNVideoTextureView;
  15 +import com.cnlive.libs.lib_cnvideo.base.IMediaPlayer;
  16 +import com.cnlive.libs.lib_cnvideo.player.AVOptions;
  17 +import com.cnlive.libs.lib_cnvideo.player.widget.CNVideoTextureView;
  18 +
  19 +/**
  20 + * This is a demo activity of PLVideoTextureView
  21 + */
  22 +public class CNVideoTextureActivity extends VideoPlayerBaseActivity {
  23 +
  24 + private static final int MESSAGE_ID_RECONNECTING = 0x01;
  25 +
  26 + private MediaController mMediaController;
  27 + private CNVideoTextureView mVideoView;
  28 + private Toast mToast = null;
  29 + private String mVideoPath = null;
  30 + private int mRotation = 0;
  31 + private int mDisplayAspectRatio = ICNVideoTextureView.ASPECT_RATIO_FIT_PARENT; //default
  32 + private View mLoadingView;
  33 + private View mCoverView = null;
  34 + private boolean mIsActivityPaused = true;
  35 +
  36 + @Override
  37 + protected void onCreate(Bundle savedInstanceState) {
  38 + super.onCreate(savedInstanceState);
  39 + setContentView(R.layout.activity_pl_video_texture);
  40 + mVideoView = (CNVideoTextureView) findViewById(R.id.VideoView);
  41 + mLoadingView = findViewById(R.id.LoadingView);
  42 + mVideoView.setBufferingIndicator(mLoadingView);
  43 + mLoadingView.setVisibility(View.VISIBLE);
  44 + mCoverView = (ImageView) findViewById(R.id.CoverView);
  45 + mVideoView.setCoverView(mCoverView);
  46 +
  47 + mVideoPath = getIntent().getStringExtra("videoPath");
  48 +
  49 + // If you want to fix display orientation such as landscape, you can use the code show as follow
  50 + //
  51 + // if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
  52 + // mVideoView.setPreviewOrientation(0);
  53 + // }
  54 + // else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
  55 + // mVideoView.setPreviewOrientation(270);
  56 + // }
  57 +
  58 + mVideoPath = getIntent().getStringExtra("videoPath");
  59 +
  60 + AVOptions options = new AVOptions();
  61 +
  62 + int isLiveStreaming = getIntent().getIntExtra("liveStreaming", 1);
  63 + // the unit of timeout is ms
  64 + options.setInteger(IAVOptions.KEY_PREPARE_TIMEOUT, 10 * 1000);
  65 + options.setInteger(IAVOptions.KEY_GET_AV_FRAME_TIMEOUT, 10 * 1000);
  66 + // Some optimization with buffering mechanism when be set to 1
  67 + options.setInteger(IAVOptions.KEY_LIVE_STREAMING, isLiveStreaming);
  68 + if (isLiveStreaming == 1) {
  69 + options.setInteger(IAVOptions.KEY_DELAY_OPTIMIZATION, 1);
  70 + }
  71 +
  72 + // 1 -> hw codec enable, 0 -> disable [recommended]
  73 + int codec = getIntent().getIntExtra("mediaCodec", 0);
  74 + options.setInteger(IAVOptions.KEY_MEDIACODEC, codec);
  75 +
  76 + // whether start play automatically after prepared, default value is 1
  77 + options.setInteger(IAVOptions.KEY_START_ON_PREPARED, 0);
  78 +
  79 + mVideoView.setAVOptions(options);
  80 +
  81 + // You can mirror the display
  82 + // mVideoView.setMirror(true);
  83 +
  84 + // You can also use a custom `MediaController` widget
  85 + mMediaController = new MediaController(this, false, isLiveStreaming == 1);
  86 + mVideoView.setMediaController(mMediaController);
  87 +
  88 + mVideoView.setOnCompletionListener(mOnCompletionListener);
  89 + mVideoView.setOnErrorListener(mOnErrorListener);
  90 +
  91 + mVideoView.setVideoPath(mVideoPath);
  92 + }
  93 +
  94 + @Override
  95 + protected void onPause() {
  96 + super.onPause();
  97 + mToast = null;
  98 + mIsActivityPaused = true;
  99 + mVideoView.pause();
  100 + }
  101 +
  102 + @Override
  103 + protected void onResume() {
  104 + super.onResume();
  105 + mIsActivityPaused = false;
  106 + }
  107 +
  108 + @Override
  109 + protected void onDestroy() {
  110 + super.onDestroy();
  111 + mVideoView.stopPlayback();
  112 + }
  113 +
  114 + public void onClickRotate(View v) {
  115 + mRotation = (mRotation + 90) % 360;
  116 + mVideoView.setDisplayOrientation(mRotation);
  117 + }
  118 +
  119 + public void onClickSwitchScreen(View v) {
  120 + mDisplayAspectRatio = (mDisplayAspectRatio + 1) % 5;
  121 + mVideoView.setDisplayAspectRatio(mDisplayAspectRatio);
  122 + switch (mVideoView.getDisplayAspectRatio()) {
  123 + case ICNVideoTextureView.ASPECT_RATIO_ORIGIN:
  124 + showToastTips("Origin mode");
  125 + break;
  126 + case ICNVideoTextureView.ASPECT_RATIO_FIT_PARENT:
  127 + showToastTips("Fit parent !");
  128 + break;
  129 + case ICNVideoTextureView.ASPECT_RATIO_PAVED_PARENT:
  130 + showToastTips("Paved parent !");
  131 + break;
  132 + case ICNVideoTextureView.ASPECT_RATIO_16_9:
  133 + showToastTips("16 : 9 !");
  134 + break;
  135 + case ICNVideoTextureView.ASPECT_RATIO_4_3:
  136 + showToastTips("4 : 3 !");
  137 + break;
  138 + default:
  139 + break;
  140 + }
  141 + }
  142 +
  143 + private IMediaPlayer.OnPreparedListener onPreparedListener = new IMediaPlayer.OnPreparedListener() {
  144 + @Override
  145 + public void onPrepared(IMediaPlayer mp) {
  146 + mVideoView.start();
  147 + }
  148 + };
  149 +
  150 + private IMediaPlayer.OnErrorListener mOnErrorListener = new IMediaPlayer.OnErrorListener() {
  151 + @Override
  152 + public boolean onError(IMediaPlayer mp, int errorCode) {
  153 + boolean isNeedReconnect = false;
  154 + switch (errorCode) {
  155 + case IMediaPlayer.ERROR_CODE_INVALID_URI:
  156 + showToastTips("Invalid URL !");
  157 + break;
  158 + case IMediaPlayer.ERROR_CODE_404_NOT_FOUND:
  159 + showToastTips("404 resource not found !");
  160 + break;
  161 + case IMediaPlayer.ERROR_CODE_CONNECTION_REFUSED:
  162 + showToastTips("Connection refused !");
  163 + break;
  164 + case IMediaPlayer.ERROR_CODE_CONNECTION_TIMEOUT:
  165 + showToastTips("Connection timeout !");
  166 + isNeedReconnect = true;
  167 + break;
  168 + case IMediaPlayer.ERROR_CODE_EMPTY_PLAYLIST:
  169 + showToastTips("Empty playlist !");
  170 + break;
  171 + case IMediaPlayer.ERROR_CODE_STREAM_DISCONNECTED:
  172 + showToastTips("Stream disconnected !");
  173 + isNeedReconnect = true;
  174 + break;
  175 + case IMediaPlayer.ERROR_CODE_IO_ERROR:
  176 + showToastTips("Network IO Error !");
  177 + isNeedReconnect = true;
  178 + break;
  179 + case IMediaPlayer.ERROR_CODE_UNAUTHORIZED:
  180 + showToastTips("Unauthorized Error !");
  181 + break;
  182 + case IMediaPlayer.ERROR_CODE_PREPARE_TIMEOUT:
  183 + showToastTips("Prepare timeout !");
  184 + isNeedReconnect = true;
  185 + break;
  186 + case IMediaPlayer.ERROR_CODE_READ_FRAME_TIMEOUT:
  187 + showToastTips("Read frame timeout !");
  188 + isNeedReconnect = true;
  189 + break;
  190 + case IMediaPlayer.MEDIA_ERROR_UNKNOWN:
  191 + break;
  192 + default:
  193 + showToastTips("unknown error !");
  194 + break;
  195 + }
  196 + // Todo pls handle the error status here, reconnect or call finish()
  197 + if (isNeedReconnect) {
  198 + sendReconnectMessage();
  199 + } else {
  200 + finish();
  201 + }
  202 + // Return true means the error has been handled
  203 + // If return false, then `onCompletion` will be called
  204 + return true;
  205 + }
  206 + };
  207 +
  208 + private IMediaPlayer.OnCompletionListener mOnCompletionListener = new IMediaPlayer.OnCompletionListener() {
  209 + @Override
  210 + public void onCompletion(IMediaPlayer plMediaPlayer) {
  211 + showToastTips("Play Completed !");
  212 + finish();
  213 + }
  214 + };
  215 +
  216 + private void showToastTips(final String tips) {
  217 + runOnUiThread(new Runnable() {
  218 + @Override
  219 + public void run() {
  220 + if (mToast != null) {
  221 + mToast.cancel();
  222 + }
  223 + mToast = Toast.makeText(CNVideoTextureActivity.this, tips, Toast.LENGTH_SHORT);
  224 + mToast.show();
  225 + }
  226 + });
  227 + }
  228 +
  229 + private void sendReconnectMessage() {
  230 + showToastTips("正在重连...");
  231 + mLoadingView.setVisibility(View.VISIBLE);
  232 + mHandler.removeCallbacksAndMessages(null);
  233 + mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_ID_RECONNECTING), 500);
  234 + }
  235 +
  236 + protected Handler mHandler = new Handler(Looper.getMainLooper()) {
  237 + @Override
  238 + public void handleMessage(Message msg) {
  239 + if (msg.what != MESSAGE_ID_RECONNECTING) {
  240 + return;
  241 + }
  242 + if (mIsActivityPaused || !Utils.isLiveStreamingAvailable()) {
  243 + finish();
  244 + return;
  245 + }
  246 + if (!Utils.isNetworkAvailable(CNVideoTextureActivity.this)) {
  247 + sendReconnectMessage();
  248 + return;
  249 + }
  250 + mVideoView.setVideoPath(mVideoPath);
  251 + mVideoView.start();
  252 + }
  253 + };
  254 +}
app/src/main/java/com/cnlive/demo/video/CNVideoViewActivity.java 0 → 100644
  1 +++ a/app/src/main/java/com/cnlive/demo/video/CNVideoViewActivity.java
  1 +package com.cnlive.demo.video;
  2 +
  3 +import android.os.Bundle;
  4 +import android.os.Handler;
  5 +import android.os.Looper;
  6 +import android.os.Message;
  7 +import android.util.Log;
  8 +import android.view.View;
  9 +import android.widget.ImageView;
  10 +import android.widget.Toast;
  11 +
  12 +import com.cnlive.demo.video.utils.Utils;
  13 +import com.cnlive.demo.video.widget.MediaController;
  14 +import com.cnlive.libs.lib_cnvideo.base.IAVOptions;
  15 +import com.cnlive.libs.lib_cnvideo.base.IDataSource;
  16 +import com.cnlive.libs.lib_cnvideo.base.IMediaPlayer;
  17 +import com.cnlive.libs.lib_cnvideo.base.IVideoView;
  18 +import com.cnlive.libs.lib_cnvideo.player.AVOptions;
  19 +import com.cnlive.libs.lib_cnvideo.player.widget.CNVideoView;
  20 +import com.cnlive.libs.util.Config;
  21 +
  22 +/**
  23 + * This is a demo activity of PLVideoView
  24 + */
  25 +public class CNVideoViewActivity extends VideoPlayerBaseActivity {
  26 +
  27 + private static final String TAG = "CNVideoViewActivity";
  28 +
  29 + private static final int MESSAGE_ID_RECONNECTING = 0x01;
  30 +
  31 + private MediaController mMediaController;
  32 + private CNVideoView mVideoView;
  33 + private Toast mToast = null;
  34 + private String mVideoPath = null;
  35 + private int mDisplayAspectRatio = CNVideoView.ASPECT_RATIO_FIT_PARENT;
  36 + private boolean mIsActivityPaused = true;
  37 + private View mLoadingView;
  38 + private View mCoverView = null;
  39 +
  40 + @Override
  41 + protected void onCreate(Bundle savedInstanceState) {
  42 + super.onCreate(savedInstanceState);
  43 + setContentView(R.layout.activity_pl_video_view);
  44 + mVideoView = (CNVideoView) findViewById(R.id.VideoView);
  45 +
  46 + mCoverView = (ImageView) findViewById(R.id.CoverView);
  47 + mVideoView.setCoverView(mCoverView);
  48 + mLoadingView = findViewById(R.id.LoadingView);
  49 + mVideoView.setBufferingIndicator(mLoadingView);
  50 + mLoadingView.setVisibility(View.VISIBLE);
  51 +
  52 + mVideoPath = getIntent().getStringExtra("videoPath");
  53 +
  54 + AVOptions options = new AVOptions();
  55 +
  56 + int isLiveStreaming = getIntent().getIntExtra("liveStreaming", 1);
  57 + // 准备超时时间,包括创建资源、建立连接、请求码流等,单位是 ms
  58 + // 默认值是:无
  59 + options.setInteger(IAVOptions.KEY_PREPARE_TIMEOUT, 10 * 1000);
  60 + // 读取视频流超时时间,单位是 ms
  61 + // 默认值是:10 * 1000
  62 + options.setInteger(IAVOptions.KEY_GET_AV_FRAME_TIMEOUT, 10 * 1000);
  63 + // 当前播放的是否为在线直播,如果是,则底层会有一些播放优化
  64 + // 默认值是:0
  65 + options.setInteger(IAVOptions.KEY_LIVE_STREAMING, isLiveStreaming);
  66 + if (isLiveStreaming == 1) {
  67 + // 是否开启"延时优化",只在在线直播流中有效
  68 + // 默认值是:0
  69 + options.setInteger(IAVOptions.KEY_DELAY_OPTIMIZATION, 1);
  70 + }
  71 + int codec = getIntent().getIntExtra("mediaCodec", 0);
  72 + // 解码方式,codec=1,硬解; codec=0, 软解
  73 + // 默认值是:0
  74 + options.setInteger(IAVOptions.KEY_MEDIACODEC, codec);
  75 + // 是否自动启动播放,如果设置为 1,则在调用 `prepareAsync` 或者 `setVideoPath` 之后自动启动播放,无需调用 `start()`
  76 + // 默认值是:1
  77 + options.setInteger(IAVOptions.KEY_START_ON_PREPARED, 0);
  78 + mVideoView.setAVOptions(options);
  79 +
  80 + // Set some listeners
  81 + mVideoView.setOnInfoListener(mOnInfoListener);
  82 + mVideoView.setOnVideoSizeChangedListener(mOnVideoSizeChangedListener);
  83 + mVideoView.setOnBufferingUpdateListener(mOnBufferingUpdateListener);
  84 + mVideoView.setOnCompletionListener(mOnCompletionListener);
  85 + mVideoView.setOnSeekCompleteListener(mOnSeekCompleteListener);
  86 + mVideoView.setOnErrorListener(mOnErrorListener);
  87 + mVideoView.setOnPreparedListener(onPreparedListener);
  88 +
  89 + //播放普通视频
  90 + mVideoView.setVideoPath(mVideoPath);
  91 +
  92 +// //播放视讯云视频
  93 +// mVideoView.setDataSource(new IDataSource() {
  94 +// @Override
  95 +// public String getId() {
  96 +// return "20161126";
  97 +// }
  98 +//
  99 +// @Override
  100 +// public String getType() {
  101 +// return Config.TYPE_VOD;
  102 +// }
  103 +//
  104 +// @Override
  105 +// public String getRate() {
  106 +// return Config.TYPE_PLAY_RATE_2;
  107 +// }
  108 +// }, false);
  109 +
  110 + // You can also use a custom `MediaController` widget
  111 + mMediaController = new MediaController(this, false, isLiveStreaming == 1);
  112 + mVideoView.setMediaController(mMediaController);
  113 + }
  114 +
  115 + @Override
  116 + protected void onResume() {
  117 + super.onResume();
  118 + mIsActivityPaused = false;
  119 + }
  120 +
  121 + @Override
  122 + protected void onPause() {
  123 + super.onPause();
  124 + mToast = null;
  125 + mIsActivityPaused = true;
  126 + mVideoView.pause();
  127 + }
  128 +
  129 + @Override
  130 + protected void onDestroy() {
  131 + super.onDestroy();
  132 + mVideoView.stopPlayback();
  133 + }
  134 +
  135 + public void onClickSwitchScreen(View v) {
  136 + mDisplayAspectRatio = (mDisplayAspectRatio + 1) % 5;
  137 + mVideoView.setDisplayAspectRatio(mDisplayAspectRatio);
  138 + switch (mVideoView.getDisplayAspectRatio()) {
  139 + case IVideoView.ASPECT_RATIO_ORIGIN:
  140 + showToastTips("Origin mode");
  141 + break;
  142 + case IVideoView.ASPECT_RATIO_FIT_PARENT:
  143 + showToastTips("Fit parent !");
  144 + break;
  145 + case IVideoView.ASPECT_RATIO_PAVED_PARENT:
  146 + showToastTips("Paved parent !");
  147 + break;
  148 + case IVideoView.ASPECT_RATIO_16_9:
  149 + showToastTips("16 : 9 !");
  150 + break;
  151 + case IVideoView.ASPECT_RATIO_4_3:
  152 + showToastTips("4 : 3 !");
  153 + break;
  154 + default:
  155 + break;
  156 + }
  157 + }
  158 +
  159 + private IMediaPlayer.OnPreparedListener onPreparedListener = new IMediaPlayer.OnPreparedListener() {
  160 + @Override
  161 + public void onPrepared(IMediaPlayer mp) {
  162 + Log.e("DemoView", "prepared");
  163 + mVideoView.start();
  164 + }
  165 + };
  166 +
  167 + private IMediaPlayer.OnInfoListener mOnInfoListener = new IMediaPlayer.OnInfoListener() {
  168 + @Override
  169 + public boolean onInfo(IMediaPlayer plMediaPlayer, int what, int extra) {
  170 + Log.d(TAG, "onInfo: " + what + ", " + extra);
  171 + return false;
  172 + }
  173 + };
  174 +
  175 + private IMediaPlayer.OnErrorListener mOnErrorListener = new IMediaPlayer.OnErrorListener() {
  176 + @Override
  177 + public boolean onError(IMediaPlayer plMediaPlayer, int errorCode) {
  178 + boolean isNeedReconnect = false;
  179 + Log.e(TAG, "Error happened, errorCode = " + errorCode);
  180 + switch (errorCode) {
  181 + case IMediaPlayer.ERROR_CODE_INVALID_URI:
  182 + showToastTips("Invalid URL !");
  183 + break;
  184 + case IMediaPlayer.ERROR_CODE_404_NOT_FOUND:
  185 + showToastTips("404 resource not found !");
  186 + break;
  187 + case IMediaPlayer.ERROR_CODE_CONNECTION_REFUSED:
  188 + showToastTips("Connection refused !");
  189 + break;
  190 + case IMediaPlayer.ERROR_CODE_CONNECTION_TIMEOUT:
  191 + showToastTips("Connection timeout !");
  192 + isNeedReconnect = true;
  193 + break;
  194 + case IMediaPlayer.ERROR_CODE_EMPTY_PLAYLIST:
  195 + showToastTips("Empty playlist !");
  196 + break;
  197 + case IMediaPlayer.ERROR_CODE_STREAM_DISCONNECTED:
  198 + showToastTips("Stream disconnected !");
  199 + isNeedReconnect = true;
  200 + break;
  201 + case IMediaPlayer.ERROR_CODE_IO_ERROR:
  202 + showToastTips("Network IO Error !");
  203 + isNeedReconnect = true;
  204 + break;
  205 + case IMediaPlayer.ERROR_CODE_UNAUTHORIZED:
  206 + showToastTips("Unauthorized Error !");
  207 + break;
  208 + case IMediaPlayer.ERROR_CODE_PREPARE_TIMEOUT:
  209 + showToastTips("Prepare timeout !");
  210 + isNeedReconnect = true;
  211 + break;
  212 + case IMediaPlayer.ERROR_CODE_READ_FRAME_TIMEOUT:
  213 + showToastTips("Read frame timeout !");
  214 + isNeedReconnect = true;
  215 + break;
  216 + case IMediaPlayer.MEDIA_ERROR_UNKNOWN:
  217 + break;
  218 + default:
  219 + showToastTips("unknown error !");
  220 + break;
  221 + }
  222 + // Todo pls handle the error status here, reconnect or call finish()
  223 + if (isNeedReconnect) {
  224 + sendReconnectMessage();
  225 + } else {
  226 + finish();
  227 + }
  228 + // Return true means the error has been handled
  229 + // If return false, then `onCompletion` will be called
  230 + return true;
  231 + }
  232 + };
  233 +
  234 + private IMediaPlayer.OnCompletionListener mOnCompletionListener = new IMediaPlayer.OnCompletionListener() {
  235 + @Override
  236 + public void onCompletion(IMediaPlayer plMediaPlayer) {
  237 + Log.d(TAG, "Play Completed !");
  238 + showToastTips("Play Completed !");
  239 + finish();
  240 + }
  241 + };
  242 +
  243 + private IMediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener = new IMediaPlayer.OnBufferingUpdateListener() {
  244 + @Override
  245 + public void onBufferingUpdate(IMediaPlayer plMediaPlayer, int precent) {
  246 + Log.d(TAG, "onBufferingUpdate: " + precent);
  247 + }
  248 + };
  249 +
  250 + private IMediaPlayer.OnSeekCompleteListener mOnSeekCompleteListener = new IMediaPlayer.OnSeekCompleteListener() {
  251 + @Override
  252 + public void onSeekComplete(IMediaPlayer plMediaPlayer) {
  253 + Log.d(TAG, "onSeekComplete !");
  254 + }
  255 + };
  256 +
  257 + private IMediaPlayer.OnVideoSizeChangedListener mOnVideoSizeChangedListener = new IMediaPlayer.OnVideoSizeChangedListener() {
  258 + @Override
  259 + public void onVideoSizeChanged(IMediaPlayer plMediaPlayer, int width, int height) {
  260 + Log.d(TAG, "onVideoSizeChanged: " + width + "," + height);
  261 + }
  262 + };
  263 +
  264 + private void showToastTips(final String tips) {
  265 + if (mIsActivityPaused) {
  266 + return;
  267 + }
  268 + runOnUiThread(new Runnable() {
  269 + @Override
  270 + public void run() {
  271 + if (mToast != null) {
  272 + mToast.cancel();
  273 + }
  274 + mToast = Toast.makeText(CNVideoViewActivity.this, tips, Toast.LENGTH_SHORT);
  275 + mToast.show();
  276 + }
  277 + });
  278 + }
  279 +
  280 + protected Handler mHandler = new Handler(Looper.getMainLooper()) {
  281 + @Override
  282 + public void handleMessage(Message msg) {
  283 + if (msg.what != MESSAGE_ID_RECONNECTING) {
  284 + return;
  285 + }
  286 + if (mIsActivityPaused || !Utils.isLiveStreamingAvailable()) {
  287 + finish();
  288 + return;
  289 + }
  290 + if (!Utils.isNetworkAvailable(CNVideoViewActivity.this)) {
  291 + sendReconnectMessage();
  292 + return;
  293 + }
  294 + mVideoView.setVideoPath(mVideoPath);
  295 + mVideoView.start();
  296 + }
  297 + };
  298 +
  299 + private void sendReconnectMessage() {
  300 + showToastTips("正在重连...");
  301 + mLoadingView.setVisibility(View.VISIBLE);
  302 + mHandler.removeCallbacksAndMessages(null);
  303 + mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_ID_RECONNECTING), 500);
  304 + }
  305 +}
app/src/main/java/com/cnlive/demo/video/MainActivity.java 0 → 100644
  1 +++ a/app/src/main/java/com/cnlive/demo/video/MainActivity.java
  1 +package com.cnlive.demo.video;
  2 +
  3 +import android.app.Activity;
  4 +import android.content.Intent;
  5 +import android.os.Bundle;
  6 +import android.support.v7.app.AppCompatActivity;
  7 +import android.view.View;
  8 +import android.widget.ArrayAdapter;
  9 +import android.widget.EditText;
  10 +import android.widget.RadioGroup;
  11 +import android.widget.Spinner;
  12 +import android.widget.TextView;
  13 +
  14 +import com.cnlive.libs.lib_cnvideo.NetworkManager;
  15 +
  16 +import java.net.UnknownHostException;
  17 +
  18 +public class MainActivity extends AppCompatActivity {
  19 +
  20 + private static final String DEFAULT_TEST_URL = "rtmp://live.hkstv.hk.lxdns.com/live/hks";
  21 +
  22 + private static final String[] DEFAULT_PLAYBACK_DOMAIN_ARRAY = {
  23 + "live.hkstv.hk.lxdns.com"
  24 + };
  25 +
  26 + private Spinner mActivitySpinner;
  27 + private EditText mEditText;
  28 + private RadioGroup mStreamingTypeRadioGroup;
  29 + private RadioGroup mDecodeTypeRadioGroup;
  30 + private NetworkManager networkManager;
  31 +
  32 + public static final String[] TEST_ACTIVITY_ARRAY = {
  33 + "CNMediaPlayerActivity",
  34 + "CNAudioPlayerActivity",
  35 + "CNVideoViewActivity",
  36 + "CNVideoTextureActivity",
  37 + "VideoViewActivity"
  38 + };
  39 +
  40 + @Override
  41 + protected void onCreate(Bundle savedInstanceState) {
  42 + super.onCreate(savedInstanceState);
  43 + setContentView(R.layout.activity_main);
  44 +
  45 +// try {
  46 +// networkManager.startDnsCacheService(this, DEFAULT_PLAYBACK_DOMAIN_ARRAY);
  47 +// } catch (UnknownHostException e) {
  48 +// e.printStackTrace();
  49 +// }
  50 +
  51 + TextView mVersionInfoTextView = (TextView) findViewById(R.id.version_info);
  52 + mVersionInfoTextView.setText("Version: " + BuildConfig.VERSION_NAME);
  53 +
  54 + mEditText = (EditText)findViewById(R.id.VideoPathEdit);
  55 + mEditText.setText(DEFAULT_TEST_URL);
  56 +
  57 + mStreamingTypeRadioGroup = (RadioGroup) findViewById(R.id.StreamingTypeRadioGroup);
  58 + mDecodeTypeRadioGroup = (RadioGroup) findViewById(R.id.DecodeTypeRadioGroup);
  59 +
  60 + mActivitySpinner = (Spinner) findViewById(R.id.TestSpinner);
  61 + ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, TEST_ACTIVITY_ARRAY);
  62 + mActivitySpinner.setAdapter(adapter);
  63 + }
  64 +
  65 + @Override
  66 + protected void onDestroy() {
  67 + super.onDestroy();
  68 +// networkManager.stopDnsCacheService(this);
  69 + }
  70 +
  71 + public void onClickLocalFile(View v) {
  72 + Intent intent = new Intent(this, VideoFileActivity.class);
  73 + startActivityForResult(intent, 0);
  74 + }
  75 +
  76 + public void onClickPlay(View v) {
  77 + String videopath = mEditText.getText().toString();
  78 + if (!"".equals(videopath)) {
  79 + jumpToPlayerActivity(videopath);
  80 + }
  81 + }
  82 +
  83 + public void jumpToPlayerActivity(String videopath) {
  84 + Class<?> cls = null;
  85 + switch (mActivitySpinner.getSelectedItemPosition()) {
  86 + case 0: cls = CNMediaPlayerActivity.class;
  87 + break;
  88 + case 1: cls = CNAudioPlayerActivity.class;
  89 + break;
  90 + case 2: cls = CNVideoViewActivity.class;
  91 + break;
  92 + case 3: cls = CNVideoTextureActivity.class;
  93 + break;
  94 + case 4: cls = VideoViewActivity.class;
  95 + break;
  96 + default:
  97 + return;
  98 + }
  99 + Intent intent = new Intent(this, cls);
  100 + intent.putExtra("videoPath", videopath);
  101 + if (mDecodeTypeRadioGroup.getCheckedRadioButtonId() == R.id.RadioHWDecode) {
  102 + intent.putExtra("mediaCodec", 1);
  103 + } else {
  104 + intent.putExtra("mediaCodec", 0);
  105 + }
  106 + if (mStreamingTypeRadioGroup.getCheckedRadioButtonId() == R.id.RadioLiveStreaming) {
  107 + intent.putExtra("liveStreaming", 1);
  108 + } else {
  109 + intent.putExtra("liveStreaming", 0);
  110 + }
  111 + startActivity(intent);
  112 + }
  113 +
  114 + @Override
  115 + protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  116 + if (resultCode != Activity.RESULT_OK) {
  117 + return;
  118 + }
  119 + String videoPath = data.getStringExtra("videoPath");
  120 + mEditText.setText(videoPath, TextView.BufferType.EDITABLE);
  121 + }
  122 +}
app/src/main/java/com/cnlive/demo/video/VideoApplication.java 0 → 100644
  1 +++ a/app/src/main/java/com/cnlive/demo/video/VideoApplication.java
  1 +package com.cnlive.demo.video;
  2 +
  3 +import android.app.Application;
  4 +
  5 +import com.cnlive.libs.util.Config;
  6 +
  7 +/**
  8 + * Created by Administrator on 2016/12/2.
  9 + */
  10 +
  11 +public class VideoApplication extends Application{
  12 + @Override
  13 + public void onCreate() {
  14 + super.onCreate();
  15 + Config.init(this, "60_irn9edco29", "69fe70bda67e059286ad509d9f5377f815955645b52f94");
  16 + }
  17 +}
app/src/main/java/com/cnlive/demo/video/VideoFileActivity.java 0 → 100644
  1 +++ a/app/src/main/java/com/cnlive/demo/video/VideoFileActivity.java
  1 +package com.cnlive.demo.video;
  2 +
  3 +import android.app.Activity;
  4 +import android.content.Context;
  5 +import android.content.Intent;
  6 +import android.database.Cursor;
  7 +import android.os.Bundle;
  8 +import android.provider.MediaStore;
  9 +import android.support.v4.app.LoaderManager;
  10 +import android.support.v4.content.CursorLoader;
  11 +import android.support.v4.content.Loader;
  12 +import android.support.v4.widget.SimpleCursorAdapter;
  13 +import android.support.v7.app.AppCompatActivity;
  14 +import android.view.View;
  15 +import android.widget.AdapterView;
  16 +import android.widget.ListView;
  17 +
  18 +public class VideoFileActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> {
  19 +
  20 + private ListView mVideoListView;
  21 + private VideoAdapter mVideoAdapter;
  22 +
  23 + @Override
  24 + protected void onCreate(Bundle savedInstanceState) {
  25 + super.onCreate(savedInstanceState);
  26 + setContentView(R.layout.activity_video_file);
  27 +
  28 + mVideoListView = (ListView) findViewById(R.id.FileListView);
  29 + mVideoAdapter = new VideoAdapter(this);
  30 +
  31 + mVideoListView.setAdapter(mVideoAdapter);
  32 + mVideoListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
  33 + @Override
  34 + public void onItemClick(AdapterView<?> parent, View view, final int position, final long id) {
  35 + Intent intent = new Intent();
  36 + intent.putExtra("videoPath", mVideoAdapter.getVideoPath(position));
  37 + setResult(Activity.RESULT_OK, intent);
  38 + finish();
  39 + }
  40 + });
  41 +
  42 + getSupportLoaderManager().initLoader(1, null, this);
  43 + }
  44 +
  45 + @Override
  46 + public Loader<Cursor> onCreateLoader(int id, Bundle args) {
  47 + return new CursorLoader(this, MediaStore.Video.Media.getContentUri("external"), null, null, null,
  48 + "UPPER(" + MediaStore.Video.Media.DATA + ")");
  49 + }
  50 +
  51 + @Override
  52 + public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
  53 + mVideoAdapter.swapCursor(data);
  54 + }
  55 +
  56 + @Override
  57 + public void onLoaderReset(Loader<Cursor> loader) {
  58 +
  59 + }
  60 +
  61 + public class VideoAdapter extends SimpleCursorAdapter {
  62 +
  63 + public VideoAdapter(Context context) {
  64 + super(context, android.R.layout.simple_list_item_1, null,
  65 + new String[]{MediaStore.Video.Media.DISPLAY_NAME, MediaStore.Video.Media.DATA},
  66 + new int[]{android.R.id.text1, android.R.id.text2}, 0);
  67 + }
  68 +
  69 + @Override
  70 + public long getItemId(int position) {
  71 + final Cursor cursor = getCursor();
  72 + if (cursor == null || cursor.getCount() == 0 || position >= cursor.getCount()) {
  73 + return 0;
  74 + }
  75 + cursor.moveToPosition(position);
  76 + return cursor.getLong(0);
  77 + }
  78 +
  79 + public String getVideoPath(int position) {
  80 + final Cursor cursor = getCursor();
  81 + if (cursor.getCount() == 0) {
  82 + return "";
  83 + }
  84 + cursor.moveToPosition(position);
  85 + return cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DATA));
  86 + }
  87 + }
  88 +
  89 +}
app/src/main/java/com/cnlive/demo/video/VideoPlayerBaseActivity.java 0 → 100644
  1 +++ a/app/src/main/java/com/cnlive/demo/video/VideoPlayerBaseActivity.java
  1 +package com.cnlive.demo.video;
  2 +
  3 +import android.os.Build;
  4 +import android.os.Bundle;
  5 +import android.support.annotation.Nullable;
  6 +import android.support.v7.app.AppCompatActivity;
  7 +import android.view.View;
  8 +import android.view.WindowManager;
  9 +
  10 +/**
  11 + * Created by kongweile on 29/10/2016.
  12 + * Auto hide and show navigation bar and status bar for API >= 19.
  13 + * Keep screen on.
  14 + */
  15 +
  16 +public class VideoPlayerBaseActivity extends AppCompatActivity {
  17 + @Override
  18 + protected void onCreate(@Nullable Bundle savedInstanceState) {
  19 + super.onCreate(savedInstanceState);
  20 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
  21 + View decorView = getWindow().getDecorView();
  22 + decorView.setSystemUiVisibility(
  23 + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
  24 + | View.SYSTEM_UI_FLAG_FULLSCREEN
  25 + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
  26 + }
  27 + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
  28 + }
  29 +}
app/src/main/java/com/cnlive/demo/video/VideoViewActivity.java 0 → 100644
  1 +++ a/app/src/main/java/com/cnlive/demo/video/VideoViewActivity.java
  1 +package com.cnlive.demo.video;
  2 +
  3 +import android.content.Intent;
  4 +import android.content.pm.ActivityInfo;
  5 +import android.os.Bundle;
  6 +import android.text.TextUtils;
  7 +import android.util.Log;
  8 +import android.util.Pair;
  9 +import android.view.View;
  10 +import android.view.ViewGroup;
  11 +import android.view.WindowManager;
  12 +import android.widget.Button;
  13 +import android.widget.Toast;
  14 +
  15 +import com.cnlive.demo.video.widget.AspectLayout;
  16 +import com.cnlive.demo.video.widget.MediaController;
  17 +import com.cnlive.libs.lib_cnvideo.base.IAVOptions;
  18 +import com.cnlive.libs.lib_cnvideo.base.IMediaPlayer;
  19 +import com.cnlive.libs.lib_cnvideo.base.Util;
  20 +import com.cnlive.libs.lib_cnvideo.player.AVOptions;
  21 +import com.cnlive.libs.lib_cnvideo.player.widget.VideoView;
  22 +
  23 +public class VideoViewActivity extends VideoPlayerBaseActivity implements
  24 + IMediaPlayer.OnCompletionListener,
  25 + IMediaPlayer.OnInfoListener,
  26 + IMediaPlayer.OnErrorListener,
  27 + IMediaPlayer.OnVideoSizeChangedListener,
  28 + IMediaPlayer.OnPreparedListener {
  29 +
  30 + private static final String TAG = "VideoViewActivity";
  31 +
  32 + private static final int REQ_DELAY_MILLS = 3000;
  33 +
  34 + private VideoView mVideoView;
  35 + private View mBufferingIndicator;
  36 + private MediaController mMediaController;
  37 + private AspectLayout mAspectLayout;
  38 + private ViewGroup.LayoutParams mLayoutParams;
  39 + private Pair<Integer, Integer> mScreenSize;
  40 +
  41 + private String mVideoPath;
  42 + private Button mBackBtn;
  43 + private long mLastPosition = 0;
  44 + private boolean mIsLiveStream = false;
  45 +
  46 + private int mReqDelayMills = REQ_DELAY_MILLS;
  47 + private boolean mIsCompleted = false;
  48 + private Runnable mVideoReconnect;
  49 +
  50 + @Override
  51 + protected void onCreate(Bundle savedInstanceState) {
  52 + super.onCreate(savedInstanceState);
  53 + setContentView(R.layout.activity_video_view);
  54 +
  55 + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
  56 +
  57 + mVideoPath = getIntent().getStringExtra("videoPath");
  58 +
  59 + Intent intent = getIntent();
  60 + String intentAction = intent.getAction();
  61 + if (!TextUtils.isEmpty(intentAction) && intentAction.equals(Intent.ACTION_VIEW)) {
  62 + mVideoPath = intent.getDataString();
  63 + }
  64 +
  65 + mVideoView = (VideoView) findViewById(R.id.video_view);
  66 + mAspectLayout = (AspectLayout) findViewById(R.id.aspect_layout);
  67 + mBufferingIndicator = findViewById(R.id.buffering_indicator);
  68 +
  69 + mBackBtn = (Button) findViewById(R.id.back_btn);
  70 + mBackBtn.setOnClickListener(new View.OnClickListener() {
  71 + @Override
  72 + public void onClick(View view) {
  73 + mVideoView.stopPlayback();
  74 + onBackPressed();
  75 + finish();
  76 + }
  77 + });
  78 +
  79 + boolean useFastForward = true;
  80 + boolean disableProgressBar = false;
  81 +
  82 + Log.i(TAG, "mVideoPath:" + mVideoPath);
  83 +
  84 + //SharedLibraryNameHelper.getInstance().renameSharedLibrary("pldroidplayer_v7a");
  85 +
  86 + AVOptions options = new AVOptions();
  87 + int codec = getIntent().getIntExtra("mediaCodec", 0);
  88 + //解码方式,codec=1,硬解;codec=0,软解
  89 + options.setInteger(IAVOptions.KEY_MEDIACODEC, codec); // 1 -> hw codec enable, 0 -> disable
  90 +
  91 + mIsLiveStream = isLiveStreaming(mVideoPath);
  92 + if (mIsLiveStream) {
  93 + // 读取视频流超时时间,单位是 ms
  94 + // 默认值是:10 * 1000
  95 + options.setInteger(IAVOptions.KEY_GET_AV_FRAME_TIMEOUT, 10 * 1000);
  96 + // 当前播放的是否为在线直播,如果是,则底层会有一些播放优化
  97 + // 默认值是:0
  98 + options.setInteger(IAVOptions.KEY_LIVE_STREAMING, 1);
  99 + }
  100 + // Tip: you can custom the variable depending on your situation
  101 + if (mIsLiveStream) {
  102 + disableProgressBar = true;
  103 + useFastForward = false;
  104 + }
  105 + mMediaController = new MediaController(this, useFastForward, disableProgressBar);
  106 +// mMediaController.setMediaPlayer(mVideoView);
  107 + mVideoView.setMediaController(mMediaController);
  108 +// mVideoView.setMediaBufferingIndicator(mBufferingIndicator);
  109 +
  110 + mVideoView.setAVOptions(options);
  111 +
  112 + mVideoView.setVideoPath(mVideoPath);
  113 +
  114 + mVideoView.setOnErrorListener(this);
  115 + mVideoView.setOnCompletionListener(this);
  116 + mVideoView.setOnInfoListener(this);
  117 + mVideoView.setOnPreparedListener(this);
  118 + mVideoView.setOnVideoSizeChangedListener(this);
  119 +
  120 + mVideoView.requestFocus();
  121 +
  122 + mBufferingIndicator.setVisibility(View.VISIBLE);
  123 + }
  124 +
  125 + @Override
  126 + public void onCompletion(IMediaPlayer mp) {
  127 + Log.d(TAG, "onCompletion");
  128 + mIsCompleted = true;
  129 + mBufferingIndicator.setVisibility(View.GONE);
  130 + mVideoView.start();
  131 + }
  132 +
  133 + @Override
  134 + public boolean onError(IMediaPlayer mp, int what) {
  135 + Log.d(TAG, "onError what=" + what + ", extra=");
  136 + switch (what) {
  137 + case IMediaPlayer.ERROR_CODE_INVALID_URI:
  138 + Toast.makeText(VideoViewActivity.this, "Invalid URL !", Toast.LENGTH_SHORT);
  139 + break;
  140 + case IMediaPlayer.ERROR_CODE_404_NOT_FOUND:
  141 + Toast.makeText(VideoViewActivity.this, "404 resource not found !", Toast.LENGTH_SHORT);
  142 + break;
  143 + case IMediaPlayer.ERROR_CODE_CONNECTION_REFUSED:
  144 + Toast.makeText(VideoViewActivity.this, "Connection refused !", Toast.LENGTH_SHORT);
  145 + break;
  146 + case IMediaPlayer.ERROR_CODE_CONNECTION_TIMEOUT:
  147 + Toast.makeText(VideoViewActivity.this, "Connection timeout !", Toast.LENGTH_SHORT);
  148 + break;
  149 + case IMediaPlayer.ERROR_CODE_EMPTY_PLAYLIST:
  150 + Toast.makeText(VideoViewActivity.this, "Empty playlist !", Toast.LENGTH_SHORT);
  151 + break;
  152 + case IMediaPlayer.ERROR_CODE_STREAM_DISCONNECTED:
  153 + Toast.makeText(VideoViewActivity.this, "Stream disconnected !", Toast.LENGTH_SHORT);
  154 + break;
  155 + case IMediaPlayer.ERROR_CODE_IO_ERROR:
  156 + Toast.makeText(VideoViewActivity.this, "Network IO Error !", Toast.LENGTH_SHORT);
  157 + break;
  158 + case IMediaPlayer.ERROR_CODE_UNAUTHORIZED:
  159 + Toast.makeText(VideoViewActivity.this, "Unauthorized Error !", Toast.LENGTH_SHORT);
  160 + break;
  161 + case IMediaPlayer.ERROR_CODE_PREPARE_TIMEOUT:
  162 + Toast.makeText(VideoViewActivity.this, "Prepare timeout !", Toast.LENGTH_SHORT);
  163 + break;
  164 + case IMediaPlayer.ERROR_CODE_READ_FRAME_TIMEOUT:
  165 + Toast.makeText(VideoViewActivity.this, "Read frame timeout !", Toast.LENGTH_SHORT);
  166 + break;
  167 + case IMediaPlayer.MEDIA_ERROR_UNKNOWN:
  168 + break;
  169 + default:
  170 + Toast.makeText(VideoViewActivity.this, "unknown error !", Toast.LENGTH_SHORT);
  171 + break;
  172 + }
  173 + if (what == -10000) {
  174 +// if (extra == PlayerCode.EXTRA_CODE_INVALID_URI || extra == PlayerCode.EXTRA_CODE_EOF) {
  175 +// if (mBufferingIndicator != null)
  176 +// mBufferingIndicator.setVisibility(View.GONE);
  177 +// return true;
  178 +// }
  179 +// if (mIsCompleted && extra == PlayerCode.EXTRA_CODE_EMPTY_PLAYLIST) {
  180 +// Log.d(TAG, "mVideoView reconnect!!!");
  181 +// mVideoView.removeCallbacks(mVideoReconnect);
  182 +// mVideoReconnect = new Runnable() {
  183 +// @Override
  184 +// public void run() {
  185 +// mVideoView.setVideoPath(mVideoPath);
  186 +// }
  187 +// };
  188 +// mVideoView.postDelayed(mVideoReconnect, mReqDelayMills);
  189 +// mReqDelayMills += 200;
  190 +// } else if (extra == PlayerCode.EXTRA_CODE_404_NOT_FOUND) {
  191 +// // NO ts exist
  192 +// if (mBufferingIndicator != null)
  193 +// mBufferingIndicator.setVisibility(View.GONE);
  194 +// } else if (extra == PlayerCode.EXTRA_CODE_IO_ERROR) {
  195 +// // NO rtmp stream exist
  196 +// if (mBufferingIndicator != null)
  197 +// mBufferingIndicator.setVisibility(View.GONE);
  198 +// }
  199 + }
  200 + // return true means you handle the onError, hence System wouldn't handle it again(popup a dialog).
  201 + return true;
  202 + }
  203 +
  204 + @Override
  205 + public boolean onInfo(IMediaPlayer mp, int what, int extra) {
  206 +
  207 + Log.d(TAG, "onInfo what=" + what + ", extra=" + extra);
  208 +
  209 + if (what == IMediaPlayer.MEDIA_INFO_BUFFERING_START) {
  210 + Log.i(TAG, "onInfo: (MEDIA_INFO_BUFFERING_START)");
  211 + if (mBufferingIndicator != null)
  212 + mBufferingIndicator.setVisibility(View.VISIBLE);
  213 + } else if (what == IMediaPlayer.MEDIA_INFO_BUFFERING_END) {
  214 + Log.i(TAG, "onInfo: (MEDIA_INFO_BUFFERING_END)");
  215 + if (mBufferingIndicator != null)
  216 + mBufferingIndicator.setVisibility(View.GONE);
  217 + } else if (what == IMediaPlayer.MEDIA_INFO_AUDIO_RENDERING_START) {
  218 + Toast.makeText(this, "Audio Start", Toast.LENGTH_LONG).show();
  219 + Log.i(TAG, "duration:" + mVideoView.getDuration());
  220 + } else if (what == IMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
  221 + Toast.makeText(this, "Video Start", Toast.LENGTH_LONG).show();
  222 + Log.i(TAG, "duration:" + mVideoView.getDuration());
  223 + }
  224 +
  225 + return true;
  226 + }
  227 +
  228 + @Override
  229 + public void onPrepared(IMediaPlayer mp) {
  230 + Log.d(TAG, "onPrepared");
  231 + mBufferingIndicator.setVisibility(View.GONE);
  232 + mReqDelayMills = REQ_DELAY_MILLS;
  233 + }
  234 +
  235 + @Override
  236 + public void onResume() {
  237 + super.onResume();
  238 + mReqDelayMills = REQ_DELAY_MILLS;
  239 + if (mVideoView != null && !mIsLiveStream && mLastPosition != 0) {
  240 + mVideoView.seekTo(mLastPosition);
  241 + mVideoView.start();
  242 + }
  243 + }
  244 +
  245 + @Override
  246 + public void onPause() {
  247 + if (mVideoView != null) {
  248 + mLastPosition = mVideoView.getCurrentPosition();
  249 + mVideoView.pause();
  250 + }
  251 + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
  252 + super.onPause();
  253 + }
  254 +
  255 + @Override
  256 + public void onVideoSizeChanged(IMediaPlayer iMediaPlayer, int width, int height) {
  257 +
  258 + Log.i(TAG, "onVideoSizeChanged " + iMediaPlayer.getVideoWidth() + "x" + iMediaPlayer.getVideoHeight() + ",width:" + width + ",height:" + height);
  259 +
  260 + /*
  261 + if (width > height) {
  262 + // land video
  263 + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
  264 + } else {
  265 + // port video
  266 + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
  267 + }*/
  268 +
  269 + mScreenSize = Util.getResolution(this);
  270 +
  271 + if (width < mScreenSize.first) {
  272 + height = mScreenSize.first * height / width;
  273 + width = mScreenSize.first;
  274 + }
  275 +
  276 + if (width * height < mScreenSize.first * mScreenSize.second) {
  277 + width = mScreenSize.second * width / height;
  278 + height = mScreenSize.second;
  279 + }
  280 +
  281 + mLayoutParams = mAspectLayout.getLayoutParams();
  282 + mLayoutParams.width = width;
  283 + mLayoutParams.height = height;
  284 + mAspectLayout.setLayoutParams(mLayoutParams);
  285 + }
  286 +
  287 + private boolean isLiveStreaming(String url) {
  288 + if (url.startsWith("rtmp://")
  289 + || (url.startsWith("http://") && url.endsWith(".m3u8"))
  290 + || (url.startsWith("http://") && url.endsWith(".flv"))) {
  291 + return true;
  292 + }
  293 + return false;
  294 + }
  295 +}
app/src/main/java/com/cnlive/demo/video/utils/Utils.java 0 → 100644
  1 +++ a/app/src/main/java/com/cnlive/demo/video/utils/Utils.java
  1 +package com.cnlive.demo.video.utils;
  2 +
  3 +import android.content.Context;
  4 +import android.net.ConnectivityManager;
  5 +import android.net.NetworkInfo;
  6 +
  7 +public class Utils {
  8 +
  9 + public static boolean isNetworkAvailable(Context context) {
  10 + ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
  11 + NetworkInfo netInfo = cm.getActiveNetworkInfo();
  12 + return netInfo != null && netInfo.isConnectedOrConnecting();
  13 + }
  14 +
  15 + /**
  16 + * Is the live streaming still available
  17 + * @return is the live streaming is available
  18 + */
  19 + public static boolean isLiveStreamingAvailable() {
  20 + // Todo: Please ask your app server, is the live streaming still available
  21 + return true;
  22 + }
  23 +}
app/src/main/java/com/cnlive/demo/video/widget/AspectLayout.java 0 → 100644
  1 +++ a/app/src/main/java/com/cnlive/demo/video/widget/AspectLayout.java
  1 +package com.cnlive.demo.video.widget;
  2 +
  3 +import android.annotation.TargetApi;
  4 +import android.content.Context;
  5 +import android.graphics.Rect;
  6 +import android.util.AttributeSet;
  7 +import android.util.Log;
  8 +import android.util.Pair;
  9 +import android.widget.RelativeLayout;
  10 +
  11 +import static com.cnlive.libs.lib_cnvideo.base.Util.getResolution;
  12 +
  13 +/**
  14 + * Created by jerikc on 15/11/22.
  15 + */
  16 +public class AspectLayout extends RelativeLayout {
  17 +
  18 + private static final String TAG = "AspectLayout";
  19 +
  20 + private int mWidthMeasureSpec;
  21 +
  22 + private int mRootHeight = 0;
  23 + private int mRootWidth = 0;
  24 +
  25 + public AspectLayout(Context context) {
  26 + super(context);
  27 + initialize(context);
  28 + }
  29 +
  30 + public AspectLayout(Context context, AttributeSet attrs) {
  31 + super(context, attrs);
  32 + initialize(context);
  33 + }
  34 +
  35 + public AspectLayout(Context context, AttributeSet attrs, int defStyleAttr) {
  36 + super(context, attrs, defStyleAttr);
  37 + initialize(context);
  38 + }
  39 +
  40 + private void initialize(Context ctx) {
  41 + }
  42 +
  43 + @TargetApi(21)
  44 + public AspectLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
  45 + super(context, attrs, defStyleAttr, defStyleRes);
  46 + }
  47 +
  48 + @Override
  49 + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  50 + Log.d(TAG, "onMeasure" + " width=[" + MeasureSpec.toString(widthMeasureSpec) +
  51 + "] height=[" + MeasureSpec.toString(heightMeasureSpec) + "]");
  52 +
  53 + Rect r = new Rect();
  54 + getWindowVisibleDisplayFrame(r);
  55 + Pair<Integer, Integer> screenSize = getResolution(getContext());
  56 +
  57 + if (mRootWidth == 0 && mRootHeight == 0) {
  58 + mRootWidth = getRootView().getWidth();
  59 + mRootHeight = getRootView().getHeight();
  60 + }
  61 + int totalHeight = 0;
  62 +
  63 + if (screenSize.first > screenSize.second) {
  64 + // land
  65 + totalHeight = mRootWidth > mRootHeight ? mRootHeight : mRootWidth;
  66 + } else {
  67 + // port
  68 + totalHeight = mRootWidth < mRootHeight ? mRootHeight : mRootWidth;
  69 + }
  70 +
  71 + int nowHeight = r.bottom - r.top;
  72 +
  73 + if (totalHeight - nowHeight > totalHeight / 4) {
  74 + // soft keyboard show
  75 + super.onMeasure(mWidthMeasureSpec, MeasureSpec.makeMeasureSpec(nowHeight + totalHeight - nowHeight, MeasureSpec.EXACTLY));
  76 + return;
  77 + } else {
  78 + // soft keyboard hide
  79 + }
  80 +
  81 + mWidthMeasureSpec = widthMeasureSpec;
  82 +
  83 + super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  84 + }
  85 +}
app/src/main/java/com/cnlive/demo/video/widget/MediaController.java 0 → 100644
  1 +++ a/app/src/main/java/com/cnlive/demo/video/widget/MediaController.java
  1 +package com.cnlive.demo.video.widget;
  2 +
  3 +import android.annotation.SuppressLint;
  4 +import android.content.Context;
  5 +import android.content.res.Resources;
  6 +import android.graphics.Rect;
  7 +import android.media.AudioManager;
  8 +import android.os.Build;
  9 +import android.os.Handler;
  10 +import android.os.Message;
  11 +import android.util.AttributeSet;
  12 +import android.util.Log;
  13 +import android.view.Gravity;
  14 +import android.view.KeyEvent;
  15 +import android.view.LayoutInflater;
  16 +import android.view.MotionEvent;
  17 +import android.view.View;
  18 +import android.widget.FrameLayout;
  19 +import android.widget.ImageButton;
  20 +import android.widget.PopupWindow;
  21 +import android.widget.ProgressBar;
  22 +import android.widget.SeekBar;
  23 +import android.widget.TextView;
  24 +
  25 +import com.cnlive.libs.lib_cnvideo.base.ICNMediaController;
  26 +
  27 +import java.util.Locale;
  28 +
  29 +/**
  30 + * You can write a custom MediaController instead of this class
  31 + * A MediaController widget must implement all the interface defined by com.pili.pldroid.player.IMediaController
  32 + */
  33 +public class MediaController extends FrameLayout implements ICNMediaController {
  34 +
  35 + private static final String TAG = "PLMediaController";
  36 + private MediaPlayerControl mPlayer;
  37 + private Context mContext;
  38 + private PopupWindow mWindow;
  39 + private int mAnimStyle;
  40 + private View mAnchor;
  41 + private View mRoot;
  42 + private ProgressBar mProgress;
  43 + private TextView mEndTime, mCurrentTime;
  44 + private long mDuration;
  45 + private boolean mShowing;
  46 + private boolean mDragging;
  47 + private boolean mInstantSeeking = true;
  48 + private static int sDefaultTimeout = 3000;
  49 + private static final int SEEK_TO_POST_DELAY_MILLIS = 200;
  50 +
  51 + private static final int FADE_OUT = 1;
  52 + private static final int SHOW_PROGRESS = 2;
  53 + private boolean mFromXml = false;
  54 + private ImageButton mPauseButton;
  55 + private ImageButton mFfwdButton;
  56 + private ImageButton mRewButton;
  57 + private ImageButton mNextButton;
  58 + private ImageButton mPrevButton;
  59 +
  60 + private boolean mUseFastForward;
  61 +
  62 + private static final int IC_MEDIA_PAUSE_ID = Resources.getSystem().getIdentifier("ic_media_pause","drawable", "android");
  63 + private static final int IC_MEDIA_PLAY_ID = Resources.getSystem().getIdentifier("ic_media_play","drawable", "android");
  64 + private static final int MEDIA_CONTROLLER_ID = Resources.getSystem().getIdentifier("media_controller", "layout", "android");
  65 + private static final int PRV_BUTTON_ID = Resources.getSystem().getIdentifier("prev","id", "android");
  66 + private static final int FFWD_BUTTON_ID = Resources.getSystem().getIdentifier("ffwd","id", "android");
  67 + private static final int NEXT_BUTTON_ID = Resources.getSystem().getIdentifier("next","id", "android");
  68 + private static final int REW_BUTTON_ID = Resources.getSystem().getIdentifier("rew","id", "android");
  69 + private static final int PAUSE_BUTTON_ID = Resources.getSystem().getIdentifier("pause","id", "android");
  70 + private static final int MEDIACONTROLLER_PROGRESS_ID = Resources.getSystem().getIdentifier("mediacontroller_progress","id", "android");
  71 + private static final int END_TIME_ID = Resources.getSystem().getIdentifier("time","id", "android");
  72 + private static final int CURRENT_TIME_ID = Resources.getSystem().getIdentifier("time_current","id", "android");
  73 +
  74 + private AudioManager mAM;
  75 + private Runnable mLastSeekBarRunnable;
  76 + private boolean mDisableProgress = false;
  77 +
  78 + public MediaController(Context context, AttributeSet attrs) {
  79 + super(context, attrs);
  80 + mRoot = this;
  81 + mFromXml = true;
  82 + initController(context);
  83 + }
  84 +
  85 + public MediaController(Context context) {
  86 + super(context);
  87 + if (!mFromXml && initController(context))
  88 + initFloatingWindow();
  89 + }
  90 +
  91 + public MediaController(Context context, boolean useFastForward, boolean disableProgressBar) {
  92 + this(context);
  93 + mUseFastForward = useFastForward;
  94 + mDisableProgress = disableProgressBar;
  95 + }
  96 +
  97 + public MediaController(Context context, boolean useFastForward) {
  98 + this(context);
  99 + mUseFastForward = useFastForward;
  100 + }
  101 +
  102 + private boolean initController(Context context) {
  103 + mUseFastForward = true;
  104 + mContext = context.getApplicationContext();
  105 + mAM = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
  106 + return true;
  107 + }
  108 +
  109 + @Override
  110 + public void onFinishInflate() {
  111 + if (mRoot != null)
  112 + initControllerView(mRoot);
  113 + super.onFinishInflate();
  114 + }
  115 +
  116 + private void initFloatingWindow() {
  117 + mWindow = new PopupWindow(mContext);
  118 + mWindow.setFocusable(false);
  119 + mWindow.setBackgroundDrawable(null);
  120 + mWindow.setOutsideTouchable(true);
  121 + mAnimStyle = android.R.style.Animation;
  122 + }
  123 +
  124 + /**
  125 + * Create the view that holds the widgets that control playback. Derived
  126 + * classes can override this to create their own.
  127 + *
  128 + * @return The controller view.
  129 + */
  130 + protected View makeControllerView() {
  131 + return ((LayoutInflater) mContext
  132 + .getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(MEDIA_CONTROLLER_ID, this);
  133 + }
  134 +
  135 + private void initControllerView(View v) {
  136 + // By default these are hidden.
  137 + mPrevButton = (ImageButton) v.findViewById(PRV_BUTTON_ID);
  138 + if (mPrevButton != null) {
  139 + mPrevButton.setVisibility(View.GONE);
  140 + }
  141 + mNextButton = (ImageButton) v.findViewById(NEXT_BUTTON_ID);
  142 + if (mNextButton != null) {
  143 + mNextButton.setVisibility(View.GONE);
  144 + }
  145 +
  146 + mFfwdButton = (ImageButton) v.findViewById(FFWD_BUTTON_ID);
  147 + if (mFfwdButton != null) {
  148 + mFfwdButton.setOnClickListener(mFfwdListener);
  149 + if (!mFromXml) {
  150 + mFfwdButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
  151 + }
  152 + }
  153 +
  154 + mRewButton = (ImageButton) v.findViewById(REW_BUTTON_ID);
  155 + if (mRewButton != null) {
  156 + mRewButton.setOnClickListener(mRewListener);
  157 + if (!mFromXml) {
  158 + mRewButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
  159 + }
  160 + }
  161 + mPauseButton = (ImageButton) v.findViewById(PAUSE_BUTTON_ID);
  162 + if (mPauseButton != null) {
  163 + mPauseButton.requestFocus();
  164 + mPauseButton.setOnClickListener(mPauseListener);
  165 + }
  166 +
  167 + mProgress = (ProgressBar) v.findViewById(MEDIACONTROLLER_PROGRESS_ID);
  168 + if (mProgress != null) {
  169 + if (mProgress instanceof SeekBar) {
  170 + SeekBar seeker = (SeekBar) mProgress;
  171 + seeker.setOnSeekBarChangeListener(mSeekListener);
  172 + seeker.setThumbOffset(1);
  173 + }
  174 + mProgress.setMax(1000);
  175 + mProgress.setEnabled(!mDisableProgress);
  176 + }
  177 +
  178 + mEndTime = (TextView) v.findViewById(END_TIME_ID);
  179 + mCurrentTime = (TextView) v.findViewById(CURRENT_TIME_ID);
  180 + }
  181 +
  182 + /**
  183 + * Control the action when the seekbar dragged by user
  184 + *
  185 + * @param seekWhenDragging
  186 + * True the media will seek periodically
  187 + */
  188 + public void setInstantSeeking(boolean seekWhenDragging) {
  189 + mInstantSeeking = seekWhenDragging;
  190 + }
  191 +
  192 + private void disableUnsupportedButtons() {
  193 + try {
  194 + if (mPauseButton != null && !mPlayer.canPause())
  195 + mPauseButton.setEnabled(false);
  196 + } catch (IncompatibleClassChangeError ex) {
  197 + }
  198 + }
  199 +
  200 + /**
  201 + * <p>
  202 + * Change the animation style resource for this controller.
  203 + * </p>
  204 + *
  205 + * <p>
  206 + * If the controller is showing, calling this method will take effect only
  207 + * the next time the controller is shown.
  208 + * </p>
  209 + *
  210 + * @param animationStyle
  211 + * animation style to use when the controller appears and disappears.
  212 + * Set to -1 for the default animation, 0 for no animation,
  213 + * or a resource identifier for an explicit animation.
  214 + *
  215 + */
  216 + public void setAnimationStyle(int animationStyle) {
  217 + mAnimStyle = animationStyle;
  218 + }
  219 +
  220 + public interface OnShownListener {
  221 + public void onShown();
  222 + }
  223 +
  224 + private OnShownListener mShownListener;
  225 +
  226 + public void setOnShownListener(OnShownListener l) {
  227 + mShownListener = l;
  228 + }
  229 +
  230 + public interface OnHiddenListener {
  231 + public void onHidden();
  232 + }
  233 +
  234 + private OnHiddenListener mHiddenListener;
  235 +
  236 + public void setOnHiddenListener(OnHiddenListener l) {
  237 + mHiddenListener = l;
  238 + }
  239 +
  240 + @SuppressLint("HandlerLeak")
  241 + private Handler mHandler = new Handler() {
  242 + @Override
  243 + public void handleMessage(Message msg) {
  244 + long pos;
  245 + switch (msg.what) {
  246 + case FADE_OUT:
  247 + hide();
  248 + break;
  249 + case SHOW_PROGRESS:
  250 + pos = setProgress();
  251 + if (!mDragging && mShowing) {
  252 + msg = obtainMessage(SHOW_PROGRESS);
  253 + sendMessageDelayed(msg, 1000 - (pos % 1000));
  254 + updatePausePlay();
  255 + }
  256 + break;
  257 + }
  258 + }
  259 + };
  260 +
  261 + private long setProgress() {
  262 + if (mPlayer == null || mDragging)
  263 + return 0;
  264 +
  265 + long position = mPlayer.getCurrentPosition();
  266 + long duration = mPlayer.getDuration();
  267 + if (mProgress != null) {
  268 + if (duration > 0) {
  269 + long pos = 1000L * position / duration;
  270 + mProgress.setProgress((int) pos);
  271 + }
  272 + int percent = mPlayer.getBufferPercentage();
  273 + mProgress.setSecondaryProgress(percent * 10);
  274 + }
  275 +
  276 + mDuration = duration;
  277 +
  278 + if (mEndTime != null)
  279 + mEndTime.setText(generateTime(mDuration));
  280 + if (mCurrentTime != null)
  281 + mCurrentTime.setText(generateTime(position));
  282 +
  283 + return position;
  284 + }
  285 +
  286 + private static String generateTime(long position) {
  287 + int totalSeconds = (int) (position / 1000);
  288 +
  289 + int seconds = totalSeconds % 60;
  290 + int minutes = (totalSeconds / 60) % 60;
  291 + int hours = totalSeconds / 3600;
  292 +
  293 + if (hours > 0) {
  294 + return String.format(Locale.US, "%02d:%02d:%02d", hours, minutes,
  295 + seconds).toString();
  296 + } else {
  297 + return String.format(Locale.US, "%02d:%02d", minutes, seconds)
  298 + .toString();
  299 + }
  300 + }
  301 +
  302 + @Override
  303 + public boolean onTouchEvent(MotionEvent event) {
  304 + show(sDefaultTimeout);
  305 + return true;
  306 + }
  307 +
  308 + @Override
  309 + public boolean onTrackballEvent(MotionEvent ev) {
  310 + show(sDefaultTimeout);
  311 + return false;
  312 + }
  313 +
  314 + @Override
  315 + public boolean dispatchKeyEvent(KeyEvent event) {
  316 + int keyCode = event.getKeyCode();
  317 + if (event.getRepeatCount() == 0
  318 + && (keyCode == KeyEvent.KEYCODE_HEADSETHOOK
  319 + || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_SPACE)) {
  320 + doPauseResume();
  321 + show(sDefaultTimeout);
  322 + if (mPauseButton != null)
  323 + mPauseButton.requestFocus();
  324 + return true;
  325 + } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) {
  326 + if (mPlayer.isPlaying()) {
  327 + mPlayer.pause();
  328 + updatePausePlay();
  329 + }
  330 + return true;
  331 + } else if (keyCode == KeyEvent.KEYCODE_BACK
  332 + || keyCode == KeyEvent.KEYCODE_MENU) {
  333 + hide();
  334 + return true;
  335 + } else {
  336 + show(sDefaultTimeout);
  337 + }
  338 + return super.dispatchKeyEvent(event);
  339 + }
  340 +
  341 + private OnClickListener mPauseListener = new OnClickListener() {
  342 + public void onClick(View v) {
  343 + doPauseResume();
  344 + show(sDefaultTimeout);
  345 + }
  346 + };
  347 +
  348 + private void updatePausePlay() {
  349 + if (mRoot == null || mPauseButton == null)
  350 + return;
  351 +
  352 + if (mPlayer.isPlaying())
  353 + mPauseButton.setImageResource(IC_MEDIA_PAUSE_ID);
  354 + else
  355 + mPauseButton.setImageResource(IC_MEDIA_PLAY_ID);
  356 + }
  357 +
  358 + private void doPauseResume() {
  359 + if (mPlayer.isPlaying())
  360 + mPlayer.pause();
  361 + else
  362 + mPlayer.start();
  363 + updatePausePlay();
  364 + }
  365 +
  366 + private SeekBar.OnSeekBarChangeListener mSeekListener = new SeekBar.OnSeekBarChangeListener() {
  367 +
  368 + public void onStartTrackingTouch(SeekBar bar) {
  369 + mDragging = true;
  370 + show(3600000);
  371 + mHandler.removeMessages(SHOW_PROGRESS);
  372 + if (mInstantSeeking)
  373 + mAM.setStreamMute(AudioManager.STREAM_MUSIC, true);
  374 + }
  375 +
  376 + public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
  377 + if (!fromuser)
  378 + return;
  379 +
  380 + final long newposition = (long) (mDuration * progress) / 1000;
  381 + String time = generateTime(newposition);
  382 + if (mInstantSeeking) {
  383 + mHandler.removeCallbacks(mLastSeekBarRunnable);
  384 + mLastSeekBarRunnable = new Runnable() {
  385 + @Override
  386 + public void run() {
  387 + mPlayer.seekTo(newposition);
  388 + }
  389 + };
  390 + mHandler.postDelayed(mLastSeekBarRunnable, SEEK_TO_POST_DELAY_MILLIS);
  391 + }
  392 + if (mCurrentTime != null)
  393 + mCurrentTime.setText(time);
  394 + }
  395 +
  396 + public void onStopTrackingTouch(SeekBar bar) {
  397 + if (!mInstantSeeking)
  398 + mPlayer.seekTo(mDuration * bar.getProgress() / 1000);
  399 +
  400 + show(sDefaultTimeout);
  401 + mHandler.removeMessages(SHOW_PROGRESS);
  402 + mAM.setStreamMute(AudioManager.STREAM_MUSIC, false);
  403 + mDragging = false;
  404 + mHandler.sendEmptyMessageDelayed(SHOW_PROGRESS, 1000);
  405 + }
  406 + };
  407 +
  408 + private OnClickListener mRewListener = new OnClickListener() {
  409 + public void onClick(View v) {
  410 + long pos = mPlayer.getCurrentPosition();
  411 + pos -= 5000; // milliseconds
  412 + mPlayer.seekTo(pos);
  413 + setProgress();
  414 +
  415 + show(sDefaultTimeout);
  416 + }
  417 + };
  418 +
  419 + private OnClickListener mFfwdListener = new OnClickListener() {
  420 + public void onClick(View v) {
  421 + long pos = mPlayer.getCurrentPosition();
  422 + pos += 15000; // milliseconds
  423 + mPlayer.seekTo(pos);
  424 + setProgress();
  425 +
  426 + show(sDefaultTimeout);
  427 + }
  428 + };
  429 +
  430 + /**
  431 + * Set the view that acts as the anchor for the control view.
  432 + *
  433 + * - This can for example be a VideoView, or your Activity's main view.
  434 + * - AudioPlayer has no anchor view, so the view parameter will be null.
  435 + *
  436 + * @param view
  437 + * The view to which to anchor the controller when it is visible.
  438 + */
  439 + @Override
  440 + public void setAnchorView(View view) {
  441 + mAnchor = view;
  442 + if (mAnchor == null) {
  443 + sDefaultTimeout = 0; // show forever
  444 + }
  445 + if (!mFromXml) {
  446 + removeAllViews();
  447 + mRoot = makeControllerView();
  448 + mWindow.setContentView(mRoot);
  449 + mWindow.setWidth(LayoutParams.MATCH_PARENT);
  450 + mWindow.setHeight(LayoutParams.WRAP_CONTENT);
  451 + }
  452 + initControllerView(mRoot);
  453 + }
  454 +
  455 + @Override
  456 + public void setMediaPlayer(MediaPlayerControl player) {
  457 + mPlayer = player;
  458 + updatePausePlay();
  459 + }
  460 +
  461 + @Override
  462 + public void show() {
  463 + show(sDefaultTimeout);
  464 + }
  465 +
  466 + /**
  467 + * Show the controller on screen. It will go away automatically after
  468 + * 'timeout' milliseconds of inactivity.
  469 + *
  470 + * @param timeout
  471 + * The timeout in milliseconds. Use 0 to show the controller until hide() is called.
  472 + */
  473 + @Override
  474 + public void show(int timeout) {
  475 + if (!mShowing) {
  476 + if (mAnchor != null && mAnchor.getWindowToken() != null) {
  477 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
  478 + mAnchor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
  479 + }
  480 + }
  481 + if (mPauseButton != null)
  482 + mPauseButton.requestFocus();
  483 + disableUnsupportedButtons();
  484 +
  485 + if (mFromXml) {
  486 + setVisibility(View.VISIBLE);
  487 + } else {
  488 + int[] location = new int[2];
  489 +
  490 + if (mAnchor != null) {
  491 + mAnchor.getLocationOnScreen(location);
  492 + Rect anchorRect = new Rect(location[0], location[1],
  493 + location[0] + mAnchor.getWidth(), location[1]
  494 + + mAnchor.getHeight());
  495 +
  496 + mWindow.setAnimationStyle(mAnimStyle);
  497 + mWindow.showAtLocation(mAnchor, Gravity.BOTTOM,
  498 + anchorRect.left, 0);
  499 + } else {
  500 + Rect anchorRect = new Rect(location[0], location[1],
  501 + location[0] + mRoot.getWidth(), location[1]
  502 + + mRoot.getHeight());
  503 +
  504 + mWindow.setAnimationStyle(mAnimStyle);
  505 + mWindow.showAtLocation(mRoot, Gravity.BOTTOM,
  506 + anchorRect.left, 0);
  507 + }
  508 + }
  509 + mShowing = true;
  510 + if (mShownListener != null)
  511 + mShownListener.onShown();
  512 + }
  513 + updatePausePlay();
  514 + mHandler.sendEmptyMessage(SHOW_PROGRESS);
  515 +
  516 + if (timeout != 0) {
  517 + mHandler.removeMessages(FADE_OUT);
  518 + mHandler.sendMessageDelayed(mHandler.obtainMessage(FADE_OUT),
  519 + timeout);
  520 + }
  521 + }
  522 +
  523 + @Override
  524 + public boolean isShowing() {
  525 + return mShowing;
  526 + }
  527 +
  528 + @Override
  529 + public void hide() {
  530 + if (mShowing) {
  531 + if (mAnchor != null) {
  532 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
  533 + //mAnchor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
  534 + }
  535 + }
  536 + try {
  537 + mHandler.removeMessages(SHOW_PROGRESS);
  538 + if (mFromXml)
  539 + setVisibility(View.GONE);
  540 + else
  541 + mWindow.dismiss();
  542 + } catch (IllegalArgumentException ex) {
  543 + Log.d(TAG, "MediaController already removed");
  544 + }
  545 + mShowing = false;
  546 + if (mHiddenListener != null)
  547 + mHiddenListener.onHidden();
  548 + }
  549 + }
  550 +
  551 + @Override
  552 + public void setEnabled(boolean enabled) {
  553 + if (mPauseButton != null) {
  554 + mPauseButton.setEnabled(enabled);
  555 + }
  556 + if (mFfwdButton != null) {
  557 + mFfwdButton.setEnabled(enabled);
  558 + }
  559 + if (mRewButton != null) {
  560 + mRewButton.setEnabled(enabled);
  561 + }
  562 + if (mProgress != null && !mDisableProgress)
  563 + mProgress.setEnabled(enabled);
  564 + disableUnsupportedButtons();
  565 + super.setEnabled(enabled);
  566 + }
  567 +}
app/src/main/jniLibs/arm64-v8a/libpldroidplayer.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/armeabi-v7a/libpldroidplayer.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/armeabi/libpldroidplayer.so 0 → 100644
No preview for this file type
app/src/main/jniLibs/x86/libpldroidplayer.so 0 → 100644
No preview for this file type
app/src/main/res/drawable/audio.jpg 0 → 100644

48.3 KB

app/src/main/res/drawable/ic_rotate_right.png 0 → 100644

1.95 KB

app/src/main/res/drawable/ic_switch_screen.png 0 → 100644

1.77 KB

app/src/main/res/drawable/thumbnail.png 0 → 100644

24.3 KB

app/src/main/res/layout/activity_audio_player.xml 0 → 100644
  1 +++ a/app/src/main/res/layout/activity_audio_player.xml
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:layout_width="match_parent"
  4 + android:layout_height="match_parent"
  5 + android:orientation="vertical">
  6 +
  7 + <ImageView
  8 + android:layout_width="wrap_content"
  9 + android:layout_height="wrap_content"
  10 + android:src="@drawable/audio"
  11 + android:layout_margin="20dp"/>
  12 +
  13 + <LinearLayout
  14 + android:id="@+id/LoadingView"
  15 + android:layout_width="match_parent"
  16 + android:layout_height="wrap_content"
  17 + android:layout_gravity="center"
  18 + android:gravity="center"
  19 + android:orientation="horizontal">
  20 + <ProgressBar
  21 + android:layout_width="wrap_content"
  22 + android:layout_height="wrap_content"
  23 + android:layout_marginRight="5dp"/>
  24 + <TextView
  25 + android:layout_width="wrap_content"
  26 + android:layout_height="wrap_content"
  27 + android:layout_marginLeft="5dp"
  28 + android:text="buffering"
  29 + android:textColor="@android:color/black"
  30 + android:textSize="20sp"/>
  31 + </LinearLayout>
  32 +
  33 + <include
  34 + layout="@layout/layout_buttons"
  35 + android:layout_width="match_parent"
  36 + android:layout_height="wrap_content"
  37 + android:layout_margin="10dp"
  38 + android:layout_gravity="bottom" />
  39 +
  40 +</FrameLayout>
app/src/main/res/layout/activity_main.xml 0 → 100644
  1 +++ a/app/src/main/res/layout/activity_main.xml
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:layout_width="match_parent"
  4 + android:layout_height="match_parent"
  5 + android:orientation="vertical">
  6 +
  7 + <TextView
  8 + android:id="@+id/version_info"
  9 + android:layout_width="match_parent"
  10 + android:layout_height="wrap_content"
  11 + android:layout_margin="15dp"
  12 + android:textSize="20sp"
  13 + android:textStyle="bold" />
  14 +
  15 + <TextView
  16 + android:layout_width="match_parent"
  17 + android:layout_height="wrap_content"
  18 + android:layout_margin="15dp"
  19 + android:text="@string/pls_choose_activity"
  20 + android:textSize="20sp"
  21 + android:textStyle="bold" />
  22 +
  23 + <Spinner
  24 + android:id="@+id/TestSpinner"
  25 + android:layout_width="match_parent"
  26 + android:layout_height="wrap_content"
  27 + android:layout_marginLeft="10dp" />
  28 +
  29 + <TextView
  30 + android:layout_width="match_parent"
  31 + android:layout_height="wrap_content"
  32 + android:layout_margin="15dp"
  33 + android:text="@string/pls_choose_setting"
  34 + android:textSize="20sp"
  35 + android:textStyle="bold" />
  36 +
  37 + <RadioGroup
  38 + android:id="@+id/StreamingTypeRadioGroup"
  39 + android:layout_width="match_parent"
  40 + android:layout_height="wrap_content"
  41 + android:layout_marginLeft="15dp"
  42 + android:layout_marginTop="5dp"
  43 + android:orientation="horizontal">
  44 +
  45 + <RadioButton
  46 + android:id="@+id/RadioLiveStreaming"
  47 + android:layout_width="wrap_content"
  48 + android:layout_height="wrap_content"
  49 + android:checked="true"
  50 + android:text="@string/live_streaming" />
  51 +
  52 + <RadioButton
  53 + android:id="@+id/RadioPlayback"
  54 + android:layout_width="wrap_content"
  55 + android:layout_height="wrap_content"
  56 + android:layout_marginLeft="10dp"
  57 + android:text="@string/playback" />
  58 +
  59 + </RadioGroup>
  60 +
  61 + <RadioGroup
  62 + android:id="@+id/DecodeTypeRadioGroup"
  63 + android:layout_width="match_parent"
  64 + android:layout_height="wrap_content"
  65 + android:layout_marginLeft="15dp"
  66 + android:layout_marginTop="5dp"
  67 + android:orientation="horizontal">
  68 +
  69 + <RadioButton
  70 + android:id="@+id/RadioSWDecode"
  71 + android:layout_width="wrap_content"
  72 + android:layout_height="wrap_content"
  73 + android:checked="true"
  74 + android:text="@string/sw_decode" />
  75 +
  76 + <RadioButton
  77 + android:id="@+id/RadioHWDecode"
  78 + android:layout_width="wrap_content"
  79 + android:layout_height="wrap_content"
  80 + android:layout_marginLeft="10dp"
  81 + android:text="@string/hw_decode" />
  82 +
  83 + </RadioGroup>
  84 +
  85 + <TextView
  86 + android:layout_width="match_parent"
  87 + android:layout_height="wrap_content"
  88 + android:layout_marginLeft="15dp"
  89 + android:layout_marginRight="15dp"
  90 + android:layout_marginTop="15dp"
  91 + android:text="@string/pls_choose_videopath"
  92 + android:textSize="20sp"
  93 + android:textStyle="bold" />
  94 +
  95 + <EditText
  96 + android:id="@+id/VideoPathEdit"
  97 + android:layout_width="match_parent"
  98 + android:layout_height="wrap_content"
  99 + android:layout_margin="10dp"
  100 + android:hint="@string/input_video_path"
  101 + android:padding="10sp"
  102 + android:singleLine="true"
  103 + android:textSize="18sp" />
  104 +
  105 + <LinearLayout
  106 + android:layout_width="match_parent"
  107 + android:layout_height="wrap_content"
  108 + android:layout_margin="10dp"
  109 + android:orientation="horizontal">
  110 +
  111 + <Button
  112 + android:layout_width="wrap_content"
  113 + android:layout_height="wrap_content"
  114 + android:onClick="onClickLocalFile"
  115 + android:text="@string/btn_local_file"
  116 + android:textSize="12sp" />
  117 +
  118 + <Button
  119 + android:layout_width="wrap_content"
  120 + android:layout_height="wrap_content"
  121 + android:layout_marginLeft="10dp"
  122 + android:onClick="onClickPlay"
  123 + android:text="@string/btn_click_play"
  124 + android:textSize="12sp" />
  125 +
  126 + </LinearLayout>
  127 +
  128 +</LinearLayout>
0 \ No newline at end of file 129 \ No newline at end of file
app/src/main/res/layout/activity_media_player.xml 0 → 100644
  1 +++ a/app/src/main/res/layout/activity_media_player.xml
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:layout_width="match_parent"
  4 + android:layout_height="match_parent">
  5 +
  6 + <SurfaceView
  7 + android:id="@+id/SurfaceView"
  8 + android:layout_width="match_parent"
  9 + android:layout_height="match_parent"
  10 + android:layout_gravity="center" />
  11 +
  12 + <LinearLayout
  13 + android:id="@+id/LoadingView"
  14 + android:layout_width="match_parent"
  15 + android:layout_height="wrap_content"
  16 + android:layout_gravity="center"
  17 + android:gravity="center"
  18 + android:orientation="horizontal">
  19 + <ProgressBar
  20 + android:layout_width="wrap_content"
  21 + android:layout_height="wrap_content"
  22 + android:layout_marginRight="5dp"/>
  23 + <TextView
  24 + android:layout_width="wrap_content"
  25 + android:layout_height="wrap_content"
  26 + android:layout_marginLeft="5dp"
  27 + android:text="@string/buffering"
  28 + android:textColor="@android:color/white"
  29 + android:textSize="20sp"/>
  30 + </LinearLayout>
  31 +
  32 + <include
  33 + layout="@layout/layout_buttons"
  34 + android:layout_width="match_parent"
  35 + android:layout_height="wrap_content"
  36 + android:layout_margin="10dp"
  37 + android:layout_gravity="bottom" />
  38 +
  39 +</FrameLayout>
app/src/main/res/layout/activity_pl_video_texture.xml 0 → 100644
  1 +++ a/app/src/main/res/layout/activity_pl_video_texture.xml
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:layout_width="match_parent"
  4 + android:layout_height="match_parent"
  5 + android:orientation="vertical">
  6 +
  7 + <com.cnlive.libs.lib_cnvideo.player.widget.CNVideoTextureView
  8 + android:id="@+id/VideoView"
  9 + android:layout_width="match_parent"
  10 + android:layout_height="match_parent"
  11 + android:layout_gravity="center" />
  12 +
  13 + <ImageView
  14 + android:id="@+id/CoverView"
  15 + android:layout_width="match_parent"
  16 + android:layout_height="match_parent"
  17 + android:layout_gravity="center"
  18 + android:src="@drawable/thumbnail"/>
  19 +
  20 + <LinearLayout
  21 + android:id="@+id/LoadingView"
  22 + android:layout_width="match_parent"
  23 + android:layout_height="wrap_content"
  24 + android:layout_gravity="center"
  25 + android:gravity="center"
  26 + android:orientation="horizontal">
  27 +
  28 + <ProgressBar
  29 + android:layout_width="wrap_content"
  30 + android:layout_height="wrap_content"
  31 + android:layout_marginRight="5dp" />
  32 +
  33 + <TextView
  34 + android:layout_width="wrap_content"
  35 + android:layout_height="wrap_content"
  36 + android:layout_marginLeft="5dp"
  37 + android:text="@string/buffering"
  38 + android:textColor="@android:color/white"
  39 + android:textSize="20sp" />
  40 + </LinearLayout>
  41 +
  42 + <LinearLayout
  43 + android:layout_width="wrap_content"
  44 + android:layout_height="wrap_content"
  45 + android:layout_gravity="top|right"
  46 + android:layout_margin="20dp"
  47 + android:orientation="horizontal">
  48 +
  49 + <ImageButton
  50 + android:layout_width="wrap_content"
  51 + android:layout_height="wrap_content"
  52 + android:layout_margin="5dp"
  53 + android:onClick="onClickRotate"
  54 + android:src="@drawable/ic_rotate_right" />
  55 +
  56 + <ImageButton
  57 + android:layout_width="wrap_content"
  58 + android:layout_height="wrap_content"
  59 + android:layout_margin="5dp"
  60 + android:onClick="onClickSwitchScreen"
  61 + android:src="@drawable/ic_switch_screen" />
  62 +
  63 + </LinearLayout>
  64 +
  65 +</FrameLayout>
app/src/main/res/layout/activity_pl_video_view.xml 0 → 100644
  1 +++ a/app/src/main/res/layout/activity_pl_video_view.xml
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:layout_width="match_parent"
  4 + android:layout_height="match_parent">
  5 +
  6 + <com.cnlive.libs.lib_cnvideo.player.widget.CNVideoView
  7 + android:id="@+id/VideoView"
  8 + android:layout_width="match_parent"
  9 + android:layout_height="match_parent"
  10 + android:layout_gravity="center" />
  11 +
  12 + <ImageView
  13 + android:id="@+id/CoverView"
  14 + android:layout_width="match_parent"
  15 + android:layout_height="match_parent"
  16 + android:layout_gravity="center"
  17 + android:src="@drawable/thumbnail" />
  18 +
  19 + <LinearLayout
  20 + android:id="@+id/LoadingView"
  21 + android:layout_width="match_parent"
  22 + android:layout_height="wrap_content"
  23 + android:layout_gravity="center"
  24 + android:gravity="center"
  25 + android:orientation="horizontal">
  26 +
  27 + <ProgressBar
  28 + android:layout_width="wrap_content"
  29 + android:layout_height="wrap_content"
  30 + android:layout_marginRight="5dp" />
  31 +
  32 + <TextView
  33 + android:layout_width="wrap_content"
  34 + android:layout_height="wrap_content"
  35 + android:layout_marginLeft="5dp"
  36 + android:text="@string/buffering"
  37 + android:textColor="@android:color/white"
  38 + android:textSize="20sp" />
  39 + </LinearLayout>
  40 +
  41 + <LinearLayout
  42 + android:layout_width="wrap_content"
  43 + android:layout_height="wrap_content"
  44 + android:layout_gravity="top|right"
  45 + android:layout_margin="20dp"
  46 + android:orientation="horizontal">
  47 +
  48 + <ImageButton
  49 + android:layout_width="wrap_content"
  50 + android:layout_height="wrap_content"
  51 + android:layout_margin="5dp"
  52 + android:onClick="onClickSwitchScreen"
  53 + android:src="@drawable/ic_switch_screen" />
  54 +
  55 + </LinearLayout>
  56 +
  57 +</FrameLayout>
app/src/main/res/layout/activity_video_file.xml 0 → 100644
  1 +++ a/app/src/main/res/layout/activity_video_file.xml
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:orientation="vertical" android:layout_width="match_parent"
  4 + android:layout_height="match_parent">
  5 +
  6 + <ListView
  7 + android:id="@+id/FileListView"
  8 + android:layout_width="match_parent"
  9 + android:layout_height="wrap_content"
  10 + android:choiceMode="singleChoice"
  11 + android:layout_margin="10dp" />
  12 +
  13 +</LinearLayout>
0 \ No newline at end of file 14 \ No newline at end of file
app/src/main/res/layout/activity_video_view.xml 0 → 100644
  1 +++ a/app/src/main/res/layout/activity_video_view.xml
  1 +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2 + xmlns:tools="http://schemas.android.com/tools"
  3 + android:layout_width="match_parent"
  4 + android:layout_height="match_parent"
  5 + android:background="@color/background_material_light">
  6 +
  7 + <com.cnlive.demo.video.widget.AspectLayout
  8 + android:id="@+id/aspect_layout"
  9 + android:layout_width="match_parent"
  10 + android:layout_height="match_parent">
  11 +
  12 + <com.cnlive.libs.lib_cnvideo.player.widget.CNVideoView
  13 + android:id="@+id/video_view"
  14 + android:layout_width="match_parent"
  15 + android:layout_height="match_parent"
  16 + android:layout_alignParentBottom="true"
  17 + android:layout_alignParentLeft="true"
  18 + android:layout_alignParentRight="true"
  19 + android:layout_alignParentTop="true"
  20 + android:layout_centerInParent="true" />
  21 + </com.cnlive.demo.video.widget.AspectLayout>
  22 +
  23 + <Button
  24 + android:id="@+id/back_btn"
  25 + android:layout_width="wrap_content"
  26 + android:layout_height="wrap_content"
  27 + android:layout_gravity="top|left"
  28 + android:layout_margin="20dp"
  29 + android:background="@color/background_floating_material_dark"
  30 + android:text="@string/back_title" />
  31 +
  32 + <EditText
  33 + android:layout_width="match_parent"
  34 + android:layout_height="wrap_content"
  35 + android:layout_alignParentBottom="true" />
  36 +
  37 + <LinearLayout
  38 + android:id="@+id/buffering_indicator"
  39 + android:layout_width="wrap_content"
  40 + android:layout_height="wrap_content"
  41 + android:layout_centerInParent="true"
  42 + android:layout_gravity="center"
  43 + android:focusable="false"
  44 + android:focusableInTouchMode="false"
  45 + android:orientation="vertical"
  46 + android:visibility="gone">
  47 +
  48 + <TextView
  49 + android:id="@+id/buffering_msg"
  50 + android:layout_width="wrap_content"
  51 + android:layout_height="wrap_content"
  52 + android:layout_gravity="center"
  53 + android:adjustViewBounds="true"
  54 + android:ellipsize="marquee"
  55 + android:marqueeRepeatLimit="0"
  56 + android:scaleType="centerInside"
  57 + android:singleLine="true"
  58 + android:text="@string/buffering"
  59 + android:textSize="12sp" />
  60 +
  61 + <ProgressBar
  62 + android:id="@+id/buffering_progress"
  63 + style="@android:style/Widget.ProgressBar.Large"
  64 + android:layout_width="60dip"
  65 + android:layout_height="60dip" />
  66 + </LinearLayout>
  67 +
  68 +</RelativeLayout>
0 \ No newline at end of file 69 \ No newline at end of file
app/src/main/res/layout/dialog_setting.xml 0 → 100644
  1 +++ a/app/src/main/res/layout/dialog_setting.xml
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:orientation="vertical" android:layout_width="match_parent"
  4 + android:layout_height="match_parent">
  5 +
  6 + <TextView
  7 + android:layout_width="match_parent"
  8 + android:layout_height="wrap_content"
  9 + android:text="@string/decode_config"
  10 + android:layout_margin="10dp"
  11 + android:textSize="15sp"
  12 + android:textStyle="bold" />
  13 +
  14 + <Spinner
  15 + android:id="@+id/CodecSpinner"
  16 + android:layout_width="match_parent"
  17 + android:layout_height="wrap_content"
  18 + android:layout_marginLeft="10dp"
  19 + android:layout_marginBottom="20dp" />
  20 +
  21 +</LinearLayout>
0 \ No newline at end of file 22 \ No newline at end of file
app/src/main/res/layout/layout_buttons.xml 0 → 100644
  1 +++ a/app/src/main/res/layout/layout_buttons.xml
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:layout_width="match_parent"
  4 + android:layout_height="wrap_content"
  5 + android:orientation="horizontal">
  6 +
  7 + <Button
  8 + android:id="@+id/BtnPlay"
  9 + android:layout_width="wrap_content"
  10 + android:layout_height="wrap_content"
  11 + android:layout_weight="1.0"
  12 + android:text="@string/btn_start"
  13 + android:onClick="onClickPlay" />
  14 +
  15 + <Button
  16 + android:id="@+id/BtnPause"
  17 + android:layout_width="wrap_content"
  18 + android:layout_height="wrap_content"
  19 + android:layout_weight="1.0"
  20 + android:text="@string/btn_pause"
  21 + android:onClick="onClickPause" />
  22 +
  23 + <Button
  24 + android:id="@+id/BtnResume"
  25 + android:layout_width="wrap_content"
  26 + android:layout_height="wrap_content"
  27 + android:layout_weight="1.0"
  28 + android:text="@string/btn_resume"
  29 + android:onClick="onClickResume" />
  30 +
  31 + <Button
  32 + android:id="@+id/BtnStop"
  33 + android:layout_width="wrap_content"
  34 + android:layout_height="wrap_content"
  35 + android:layout_weight="1.0"
  36 + android:text="@string/btn_stop"
  37 + android:onClick="onClickStop" />
  38 +
  39 +</LinearLayout>
app/src/main/res/mipmap-hdpi/ic_launcher.png 0 → 100644

3.34 KB

app/src/main/res/mipmap-mdpi/ic_launcher.png 0 → 100644

2.15 KB

app/src/main/res/mipmap-xhdpi/ic_launcher.png 0 → 100644

4.73 KB

app/src/main/res/mipmap-xxhdpi/ic_launcher.png 0 → 100644

7.54 KB

app/src/main/res/mipmap-xxxhdpi/ic_launcher.png 0 → 100644

10.2 KB

app/src/main/res/values-w820dp/dimens.xml 0 → 100644
  1 +++ a/app/src/main/res/values-w820dp/dimens.xml
  1 +<resources>
  2 + <!-- Example customization of dimensions originally defined in res/values/dimens.xml
  3 + (such as screen margins) for screens with more than 820dp of available width. This
  4 + would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
  5 + <dimen name="activity_horizontal_margin">64dp</dimen>
  6 +</resources>
app/src/main/res/values/colors.xml 0 → 100644
  1 +++ a/app/src/main/res/values/colors.xml
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<resources>
  3 + <color name="colorPrimary">#3F51B5</color>
  4 + <color name="colorPrimaryDark">#303F9F</color>
  5 + <color name="colorAccent">#FF4081</color>
  6 +</resources>
app/src/main/res/values/dimens.xml 0 → 100644
  1 +++ a/app/src/main/res/values/dimens.xml
  1 +<resources>
  2 + <!-- Default screen margins, per the Android Design guidelines. -->
  3 + <dimen name="activity_horizontal_margin">16dp</dimen>
  4 + <dimen name="activity_vertical_margin">16dp</dimen>
  5 +</resources>
app/src/main/res/values/strings.xml 0 → 100644
  1 +++ a/app/src/main/res/values/strings.xml
  1 +<resources>
  2 + <string name="app_name">QNVideoDemo</string>
  3 +
  4 + <string name="choose_ok">OK</string>
  5 + <string name="input_title">Input Url:</string>
  6 + <string name="back_title">BACK</string>
  7 + <string name="change_title">Change</string>
  8 + <string name="buffering">Buffering</string>
  9 + <string name="title_activity_audio_player">AudioPlayerActivity</string>
  10 + <string name="choose_video">Video</string>
  11 + <string name="choose_audio">Audio</string>
  12 +
  13 + <string name="live_streaming">直播</string>
  14 + <string name="playback">点播</string>
  15 +
  16 + <string name="play_setting">播放设置</string>
  17 + <string name="decode_config">解码配置</string>
  18 + <string name="sw_decode">软解</string>
  19 + <string name="hw_decode">硬解</string>
  20 +
  21 + <string name="dlg_ok">OK</string>
  22 + <string name="dlg_cancel">Cancel</string>
  23 +
  24 + <string name="pls_choose_activity">[请选择测试 Activity]:</string>
  25 + <string name="pls_choose_videopath">[输入或选择视频地址]:</string>
  26 + <string name="pls_choose_setting">[请选择播放配置]:</string>
  27 + <string name="input_video_path">手动输入测试视频地址</string>
  28 + <string name="btn_local_file">本地文件</string>
  29 + <string name="btn_play_setting">播放配置</string>
  30 + <string name="btn_click_play">点击播放</string>
  31 +
  32 + <string name="btn_start">开始</string>
  33 + <string name="btn_pause">暂停</string>
  34 + <string name="btn_resume">继续</string>
  35 + <string name="btn_stop">停止</string>
  36 +</resources>
app/src/main/res/values/styles.xml 0 → 100644
  1 +++ a/app/src/main/res/values/styles.xml
  1 +<resources>
  2 +
  3 + <!-- Base application theme. -->
  4 + <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
  5 + <!-- Customize your theme here. -->
  6 + <item name="colorPrimary">@color/colorPrimary</item>
  7 + <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
  8 + <item name="colorAccent">@color/colorAccent</item>
  9 + </style>
  10 +
  11 +</resources>
app/src/test/java/com/cnlive/demo/video/ExampleUnitTest.java 0 → 100644
  1 +++ a/app/src/test/java/com/cnlive/demo/video/ExampleUnitTest.java
  1 +package com.cnlive.demo.video;
  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 <a href="http://d.android.com/tools/testing">Testing documentation</a>
  11 + */
  12 +public class ExampleUnitTest {
  13 + @Test
  14 + public void addition_isCorrect() throws Exception {
  15 + assertEquals(4, 2 + 2);
  16 + }
  17 +}
0 \ No newline at end of file 18 \ No newline at end of file
build.gradle 0 → 100644
  1 +++ a/build.gradle
  1 +// Top-level build file where you can add configuration options common to all sub-projects/modules.
  2 +
  3 +buildscript {
  4 + repositories {
  5 + jcenter()
  6 + }
  7 + dependencies {
  8 + classpath 'com.android.tools.build:gradle:2.2.2'
  9 +
  10 + // NOTE: Do not place your application dependencies here; they belong
  11 + // in the individual module build.gradle files
  12 + }
  13 +}
  14 +
  15 +allprojects {
  16 + repositories {
  17 + jcenter()
  18 + }
  19 +}
  20 +
  21 +task clean(type: Delete) {
  22 + delete rootProject.buildDir
  23 +}
gradle.properties 0 → 100644
  1 +++ a/gradle.properties
  1 +# Project-wide Gradle settings.
  2 +
  3 +# IDE (e.g. Android Studio) users:
  4 +# Gradle settings configured through the IDE *will override*
  5 +# any settings specified in this file.
  6 +
  7 +# For more details on how to configure your build environment visit
  8 +# http://www.gradle.org/docs/current/userguide/build_environment.html
  9 +
  10 +# Specifies the JVM arguments used for the daemon process.
  11 +# The setting is particularly useful for tweaking memory settings.
  12 +org.gradle.jvmargs=-Xmx1536m
  13 +
  14 +# When configured, Gradle will run in incubating parallel mode.
  15 +# This option should only be used with decoupled projects. More details, visit
  16 +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
  17 +# org.gradle.parallel=true
gradle/wrapper/gradle-wrapper.jar 0 → 100644
No preview for this file type
gradle/wrapper/gradle-wrapper.properties 0 → 100644
  1 +++ a/gradle/wrapper/gradle-wrapper.properties
  1 +#Mon Dec 28 10:00:20 PST 2015
  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-2.14.1-all.zip
gradlew 0 → 100644
  1 +++ a/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 "$@"
gradlew.bat 0 → 100644
  1 +++ a/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
settings.gradle 0 → 100644
  1 +++ a/settings.gradle
  1 +include ':app'