diff --git a/app/libraries/ijkplayer-java/.gitignore b/app/libraries/ijkplayer-java/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/libraries/ijkplayer-java/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/libraries/ijkplayer-java/build.gradle b/app/libraries/ijkplayer-java/build.gradle new file mode 100644 index 0000000..8224251 --- /dev/null +++ b/app/libraries/ijkplayer-java/build.gradle @@ -0,0 +1,36 @@ +apply plugin: 'com.android.library' + +android { + // http://tools.android.com/tech-docs/new-build-system/tips + //noinspection GroovyAssignabilityCheck + compileSdkVersion rootProject.ext.compileSdkVersion + //noinspection GroovyAssignabilityCheck + buildToolsVersion rootProject.ext.buildToolsVersion + + defaultConfig { + minSdkVersion 9 + targetSdkVersion rootProject.ext.targetSdkVersion + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + buildToolsVersion '25.0.0' +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) +} + +ext { + optionalPlugins = ['tools/gradle-mvn-push.gradle', 'tools/gradle-bintray-upload.gradle']; +} + +ext.optionalPlugins.each{ value -> + def plugin_file = new File(rootProject.projectDir, value); + if (plugin_file.exists()) { + apply from: plugin_file + } +} \ No newline at end of file diff --git a/app/libraries/ijkplayer-java/gradle.properties b/app/libraries/ijkplayer-java/gradle.properties new file mode 100644 index 0000000..a6b3c5c --- /dev/null +++ b/app/libraries/ijkplayer-java/gradle.properties @@ -0,0 +1,3 @@ +POM_NAME=ijkplayer-java +POM_ARTIFACT_ID=ijkplayer-java +POM_PACKAGING=aar \ No newline at end of file diff --git a/app/libraries/ijkplayer-java/proguard-rules.pro b/app/libraries/ijkplayer-java/proguard-rules.pro new file mode 100644 index 0000000..034485d --- /dev/null +++ b/app/libraries/ijkplayer-java/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /opt/android/ADK/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/app/libraries/ijkplayer-java/src/androidTest/java/tv/danmaku/ijk/media/player/ApplicationTest.java b/app/libraries/ijkplayer-java/src/androidTest/java/tv/danmaku/ijk/media/player/ApplicationTest.java new file mode 100644 index 0000000..60d1d73 --- /dev/null +++ b/app/libraries/ijkplayer-java/src/androidTest/java/tv/danmaku/ijk/media/player/ApplicationTest.java @@ -0,0 +1,13 @@ +package tv.danmaku.ijk.media.player; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/app/libraries/ijkplayer-java/src/main/.classpath b/app/libraries/ijkplayer-java/src/main/.classpath new file mode 100644 index 0000000..b3caa8c --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/libraries/ijkplayer-java/src/main/.project b/app/libraries/ijkplayer-java/src/main/.project new file mode 100644 index 0000000..31663eb --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/.project @@ -0,0 +1,33 @@ + + + ijkplayer-java + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/app/libraries/ijkplayer-java/src/main/.settings/org.eclipse.jdt.core.prefs b/app/libraries/ijkplayer-java/src/main/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..b080d2d --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,4 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/app/libraries/ijkplayer-java/src/main/AndroidManifest.xml b/app/libraries/ijkplayer-java/src/main/AndroidManifest.xml new file mode 100644 index 0000000..c87fe47 --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/AbstractMediaPlayer.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/AbstractMediaPlayer.java new file mode 100644 index 0000000..d79a97d --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/AbstractMediaPlayer.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2013-2014 Zhang Rui + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tv.danmaku.ijk.media.player; + +import tv.danmaku.ijk.media.player.misc.IMediaDataSource; + +@SuppressWarnings("WeakerAccess") +public abstract class AbstractMediaPlayer implements IMediaPlayer { + private OnPreparedListener mOnPreparedListener; + private OnCompletionListener mOnCompletionListener; + private OnBufferingUpdateListener mOnBufferingUpdateListener; + private OnSeekCompleteListener mOnSeekCompleteListener; + private OnVideoSizeChangedListener mOnVideoSizeChangedListener; + private OnErrorListener mOnErrorListener; + private OnInfoListener mOnInfoListener; + + public final void setOnPreparedListener(OnPreparedListener listener) { + mOnPreparedListener = listener; + } + + public final void setOnCompletionListener(OnCompletionListener listener) { + mOnCompletionListener = listener; + } + + public final void setOnBufferingUpdateListener( + OnBufferingUpdateListener listener) { + mOnBufferingUpdateListener = listener; + } + + public final void setOnSeekCompleteListener(OnSeekCompleteListener listener) { + mOnSeekCompleteListener = listener; + } + + public final void setOnVideoSizeChangedListener( + OnVideoSizeChangedListener listener) { + mOnVideoSizeChangedListener = listener; + } + + public final void setOnErrorListener(OnErrorListener listener) { + mOnErrorListener = listener; + } + + public final void setOnInfoListener(OnInfoListener listener) { + mOnInfoListener = listener; + } + + public void resetListeners() { + mOnPreparedListener = null; + mOnBufferingUpdateListener = null; + mOnCompletionListener = null; + mOnSeekCompleteListener = null; + mOnVideoSizeChangedListener = null; + mOnErrorListener = null; + mOnInfoListener = null; + } + + protected final void notifyOnPrepared() { + if (mOnPreparedListener != null) + mOnPreparedListener.onPrepared(this); + } + + protected final void notifyOnCompletion() { + if (mOnCompletionListener != null) + mOnCompletionListener.onCompletion(this); + } + + protected final void notifyOnBufferingUpdate(int percent) { + if (mOnBufferingUpdateListener != null) + mOnBufferingUpdateListener.onBufferingUpdate(this, percent); + } + + protected final void notifyOnSeekComplete() { + if (mOnSeekCompleteListener != null) + mOnSeekCompleteListener.onSeekComplete(this); + } + + protected final void notifyOnVideoSizeChanged(int width, int height, + int sarNum, int sarDen) { + if (mOnVideoSizeChangedListener != null) + mOnVideoSizeChangedListener.onVideoSizeChanged(this, width, height, + sarNum, sarDen); + } + + protected final boolean notifyOnError(int what, int extra) { + return mOnErrorListener != null && mOnErrorListener.onError(this, what, extra); + } + + protected final boolean notifyOnInfo(int what, int extra) { + return mOnInfoListener != null && mOnInfoListener.onInfo(this, what, extra); + } + + public void setDataSource(IMediaDataSource mediaDataSource) { + throw new UnsupportedOperationException(); + } +} diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/AndroidMediaPlayer.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/AndroidMediaPlayer.java new file mode 100644 index 0000000..693df7b --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/AndroidMediaPlayer.java @@ -0,0 +1,418 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * Copyright (C) 2013 Zhang Rui + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tv.danmaku.ijk.media.player; + +import android.annotation.TargetApi; +import android.content.Context; +import android.media.AudioManager; +import android.media.MediaDataSource; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.Build; +import android.text.TextUtils; +import android.view.Surface; +import android.view.SurfaceHolder; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.util.Map; + +import tv.danmaku.ijk.media.player.misc.AndroidTrackInfo; +import tv.danmaku.ijk.media.player.misc.IMediaDataSource; +import tv.danmaku.ijk.media.player.misc.ITrackInfo; +import tv.danmaku.ijk.media.player.pragma.DebugLog; + +public class AndroidMediaPlayer extends AbstractMediaPlayer { + private final MediaPlayer mInternalMediaPlayer; + private final AndroidMediaPlayerListenerHolder mInternalListenerAdapter; + private String mDataSource; + private MediaDataSource mMediaDataSource; + + private final Object mInitLock = new Object(); + private boolean mIsReleased; + + private static MediaInfo sMediaInfo; + + public AndroidMediaPlayer() { + synchronized (mInitLock) { + mInternalMediaPlayer = new MediaPlayer(); + } + mInternalMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); + mInternalListenerAdapter = new AndroidMediaPlayerListenerHolder(this); + attachInternalListeners(); + } + + public MediaPlayer getInternalMediaPlayer() { + return mInternalMediaPlayer; + } + + @Override + public void setDisplay(SurfaceHolder sh) { + synchronized (mInitLock) { + if (!mIsReleased) { + mInternalMediaPlayer.setDisplay(sh); + } + } + } + + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) + @Override + public void setSurface(Surface surface) { + mInternalMediaPlayer.setSurface(surface); + } + + @Override + public void setDataSource(Context context, Uri uri) + throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { + mInternalMediaPlayer.setDataSource(context, uri); + } + + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) + @Override + public void setDataSource(Context context, Uri uri, Map headers) + throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { + mInternalMediaPlayer.setDataSource(context, uri, headers); + } + + @Override + public void setDataSource(FileDescriptor fd) + throws IOException, IllegalArgumentException, IllegalStateException { + mInternalMediaPlayer.setDataSource(fd); + } + + @Override + public void setDataSource(String path) throws IOException, + IllegalArgumentException, SecurityException, IllegalStateException { + mDataSource = path; + + Uri uri = Uri.parse(path); + String scheme = uri.getScheme(); + if (!TextUtils.isEmpty(scheme) && scheme.equalsIgnoreCase("file")) { + mInternalMediaPlayer.setDataSource(uri.getPath()); + } else { + mInternalMediaPlayer.setDataSource(path); + } + } + + @TargetApi(Build.VERSION_CODES.M) + @Override + public void setDataSource(IMediaDataSource mediaDataSource) { + releaseMediaDataSource(); + + mMediaDataSource = new MediaDataSourceProxy(mediaDataSource); + mInternalMediaPlayer.setDataSource(mMediaDataSource); + } + + @TargetApi(Build.VERSION_CODES.M) + private static class MediaDataSourceProxy extends MediaDataSource { + private final IMediaDataSource mMediaDataSource; + + public MediaDataSourceProxy(IMediaDataSource mediaDataSource) { + mMediaDataSource = mediaDataSource; + } + + @Override + public int readAt(long position, byte[] buffer, int offset, int size) throws IOException { + return mMediaDataSource.readAt(position, buffer, offset, size); + } + + @Override + public long getSize() throws IOException { + return mMediaDataSource.getSize(); + } + + @Override + public void close() throws IOException { + mMediaDataSource.close(); + } + } + + @Override + public String getDataSource() { + return mDataSource; + } + + private void releaseMediaDataSource() { + if (mMediaDataSource != null) { + try { + mMediaDataSource.close(); + } catch (IOException e) { + e.printStackTrace(); + } + mMediaDataSource = null; + } + } + + @Override + public void prepareAsync() throws IllegalStateException { + mInternalMediaPlayer.prepareAsync(); + } + + @Override + public void start() throws IllegalStateException { + mInternalMediaPlayer.start(); + } + + @Override + public void stop() throws IllegalStateException { + mInternalMediaPlayer.stop(); + } + + @Override + public void pause() throws IllegalStateException { + mInternalMediaPlayer.pause(); + } + + @Override + public void setScreenOnWhilePlaying(boolean screenOn) { + mInternalMediaPlayer.setScreenOnWhilePlaying(screenOn); + } + + @Override + public ITrackInfo[] getTrackInfo() { + return AndroidTrackInfo.fromMediaPlayer(mInternalMediaPlayer); + } + + @Override + public int getVideoWidth() { + return mInternalMediaPlayer.getVideoWidth(); + } + + @Override + public int getVideoHeight() { + return mInternalMediaPlayer.getVideoHeight(); + } + + @Override + public int getVideoSarNum() { + return 1; + } + + @Override + public int getVideoSarDen() { + return 1; + } + + @Override + public boolean isPlaying() { + try { + return mInternalMediaPlayer.isPlaying(); + } catch (IllegalStateException e) { + DebugLog.printStackTrace(e); + return false; + } + } + + @Override + public void seekTo(long msec) throws IllegalStateException { + mInternalMediaPlayer.seekTo((int) msec); + } + + @Override + public long getCurrentPosition() { + try { + return mInternalMediaPlayer.getCurrentPosition(); + } catch (IllegalStateException e) { + DebugLog.printStackTrace(e); + return 0; + } + } + + @Override + public long getDuration() { + try { + return mInternalMediaPlayer.getDuration(); + } catch (IllegalStateException e) { + DebugLog.printStackTrace(e); + return 0; + } + } + + @Override + public void release() { + mIsReleased = true; + mInternalMediaPlayer.release(); + releaseMediaDataSource(); + resetListeners(); + attachInternalListeners(); + } + + @Override + public void reset() { + try { + mInternalMediaPlayer.reset(); + } catch (IllegalStateException e) { + DebugLog.printStackTrace(e); + } + releaseMediaDataSource(); + resetListeners(); + attachInternalListeners(); + } + + @Override + public void setLooping(boolean looping) { + mInternalMediaPlayer.setLooping(looping); + } + + @Override + public boolean isLooping() { + return mInternalMediaPlayer.isLooping(); + } + + @Override + public void setVolume(float leftVolume, float rightVolume) { + mInternalMediaPlayer.setVolume(leftVolume, rightVolume); + } + + @Override + public int getAudioSessionId() { + return mInternalMediaPlayer.getAudioSessionId(); + } + + @Override + public MediaInfo getMediaInfo() { + if (sMediaInfo == null) { + MediaInfo module = new MediaInfo(); + + module.mVideoDecoder = "android"; + module.mVideoDecoderImpl = "HW"; + + module.mAudioDecoder = "android"; + module.mAudioDecoderImpl = "HW"; + + sMediaInfo = module; + } + + return sMediaInfo; + } + + @Override + public void setLogEnabled(boolean enable) { + } + + @Override + public boolean isPlayable() { + return true; + } + + /*-------------------- + * misc + */ + @Override + public void setWakeMode(Context context, int mode) { + mInternalMediaPlayer.setWakeMode(context, mode); + } + + @Override + public void setAudioStreamType(int streamtype) { + mInternalMediaPlayer.setAudioStreamType(streamtype); + } + + @Override + public void setKeepInBackground(boolean keepInBackground) { + } + + /*-------------------- + * Listeners adapter + */ + private void attachInternalListeners() { + mInternalMediaPlayer.setOnPreparedListener(mInternalListenerAdapter); + mInternalMediaPlayer + .setOnBufferingUpdateListener(mInternalListenerAdapter); + mInternalMediaPlayer.setOnCompletionListener(mInternalListenerAdapter); + mInternalMediaPlayer + .setOnSeekCompleteListener(mInternalListenerAdapter); + mInternalMediaPlayer + .setOnVideoSizeChangedListener(mInternalListenerAdapter); + mInternalMediaPlayer.setOnErrorListener(mInternalListenerAdapter); + mInternalMediaPlayer.setOnInfoListener(mInternalListenerAdapter); + } + + private class AndroidMediaPlayerListenerHolder implements + MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener, + MediaPlayer.OnBufferingUpdateListener, + MediaPlayer.OnSeekCompleteListener, + MediaPlayer.OnVideoSizeChangedListener, + MediaPlayer.OnErrorListener, MediaPlayer.OnInfoListener { + public final WeakReference mWeakMediaPlayer; + + public AndroidMediaPlayerListenerHolder(AndroidMediaPlayer mp) { + mWeakMediaPlayer = new WeakReference(mp); + } + + @Override + public boolean onInfo(MediaPlayer mp, int what, int extra) { + AndroidMediaPlayer self = mWeakMediaPlayer.get(); + return self != null && notifyOnInfo(what, extra); + + } + + @Override + public boolean onError(MediaPlayer mp, int what, int extra) { + AndroidMediaPlayer self = mWeakMediaPlayer.get(); + return self != null && notifyOnError(what, extra); + + } + + @Override + public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { + AndroidMediaPlayer self = mWeakMediaPlayer.get(); + if (self == null) + return; + + notifyOnVideoSizeChanged(width, height, 1, 1); + } + + @Override + public void onSeekComplete(MediaPlayer mp) { + AndroidMediaPlayer self = mWeakMediaPlayer.get(); + if (self == null) + return; + + notifyOnSeekComplete(); + } + + @Override + public void onBufferingUpdate(MediaPlayer mp, int percent) { + AndroidMediaPlayer self = mWeakMediaPlayer.get(); + if (self == null) + return; + + notifyOnBufferingUpdate(percent); + } + + @Override + public void onCompletion(MediaPlayer mp) { + AndroidMediaPlayer self = mWeakMediaPlayer.get(); + if (self == null) + return; + + notifyOnCompletion(); + } + + @Override + public void onPrepared(MediaPlayer mp) { + AndroidMediaPlayer self = mWeakMediaPlayer.get(); + if (self == null) + return; + + notifyOnPrepared(); + } + } +} diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IMediaPlayer.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IMediaPlayer.java new file mode 100644 index 0000000..34bc54a --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IMediaPlayer.java @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2013-2014 Zhang Rui + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tv.danmaku.ijk.media.player; + +import android.annotation.TargetApi; +import android.content.Context; +import android.net.Uri; +import android.os.Build; +import android.view.Surface; +import android.view.SurfaceHolder; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.util.Map; + +import tv.danmaku.ijk.media.player.misc.IMediaDataSource; +import tv.danmaku.ijk.media.player.misc.ITrackInfo; + +public interface IMediaPlayer { + /* + * Do not change these values without updating their counterparts in native + */ + int MEDIA_INFO_UNKNOWN = 1; + int MEDIA_INFO_STARTED_AS_NEXT = 2; + int MEDIA_INFO_VIDEO_RENDERING_START = 3; + int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; + int MEDIA_INFO_BUFFERING_START = 701; + int MEDIA_INFO_BUFFERING_END = 702; + int MEDIA_INFO_NETWORK_BANDWIDTH = 703; + int MEDIA_INFO_BAD_INTERLEAVING = 800; + int MEDIA_INFO_NOT_SEEKABLE = 801; + int MEDIA_INFO_METADATA_UPDATE = 802; + int MEDIA_INFO_TIMED_TEXT_ERROR = 900; + int MEDIA_INFO_UNSUPPORTED_SUBTITLE = 901; + int MEDIA_INFO_SUBTITLE_TIMED_OUT = 902; + + int MEDIA_INFO_VIDEO_ROTATION_CHANGED = 10001; + int MEDIA_INFO_AUDIO_RENDERING_START = 10002; + + int MEDIA_ERROR_UNKNOWN = 1; + int MEDIA_ERROR_SERVER_DIED = 100; + int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200; + int MEDIA_ERROR_IO = -1004; + int MEDIA_ERROR_MALFORMED = -1007; + int MEDIA_ERROR_UNSUPPORTED = -1010; + int MEDIA_ERROR_TIMED_OUT = -110; + + void setDisplay(SurfaceHolder sh); + + void setDataSource(Context context, Uri uri) + throws IOException, IllegalArgumentException, SecurityException, IllegalStateException; + + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) + void setDataSource(Context context, Uri uri, Map headers) + throws IOException, IllegalArgumentException, SecurityException, IllegalStateException; + + void setDataSource(FileDescriptor fd) + throws IOException, IllegalArgumentException, IllegalStateException; + + void setDataSource(String path) + throws IOException, IllegalArgumentException, SecurityException, IllegalStateException; + + String getDataSource(); + + void prepareAsync() throws IllegalStateException; + + void start() throws IllegalStateException; + + void stop() throws IllegalStateException; + + void pause() throws IllegalStateException; + + void setScreenOnWhilePlaying(boolean screenOn); + + int getVideoWidth(); + + int getVideoHeight(); + + boolean isPlaying(); + + void seekTo(long msec) throws IllegalStateException; + + long getCurrentPosition(); + + long getDuration(); + + void release(); + + void reset(); + + void setVolume(float leftVolume, float rightVolume); + + int getAudioSessionId(); + + MediaInfo getMediaInfo(); + + @SuppressWarnings("EmptyMethod") + @Deprecated + void setLogEnabled(boolean enable); + + @Deprecated + boolean isPlayable(); + + void setOnPreparedListener(OnPreparedListener listener); + + void setOnCompletionListener(OnCompletionListener listener); + + void setOnBufferingUpdateListener( + OnBufferingUpdateListener listener); + + void setOnSeekCompleteListener( + OnSeekCompleteListener listener); + + void setOnVideoSizeChangedListener( + OnVideoSizeChangedListener listener); + + void setOnErrorListener(OnErrorListener listener); + + void setOnInfoListener(OnInfoListener listener); + + /*-------------------- + * Listeners + */ + interface OnPreparedListener { + void onPrepared(IMediaPlayer mp); + } + + interface OnCompletionListener { + void onCompletion(IMediaPlayer mp); + } + + interface OnBufferingUpdateListener { + void onBufferingUpdate(IMediaPlayer mp, int percent); + } + + interface OnSeekCompleteListener { + void onSeekComplete(IMediaPlayer mp); + } + + interface OnVideoSizeChangedListener { + void onVideoSizeChanged(IMediaPlayer mp, int width, int height, + int sar_num, int sar_den); + } + + interface OnErrorListener { + boolean onError(IMediaPlayer mp, int what, int extra); + } + + interface OnInfoListener { + boolean onInfo(IMediaPlayer mp, int what, int extra); + } + + /*-------------------- + * Optional + */ + void setAudioStreamType(int streamtype); + + @Deprecated + void setKeepInBackground(boolean keepInBackground); + + int getVideoSarNum(); + + int getVideoSarDen(); + + @Deprecated + void setWakeMode(Context context, int mode); + + void setLooping(boolean looping); + + boolean isLooping(); + + /*-------------------- + * AndroidMediaPlayer: JELLY_BEAN + */ + ITrackInfo[] getTrackInfo(); + + /*-------------------- + * AndroidMediaPlayer: ICE_CREAM_SANDWICH: + */ + void setSurface(Surface surface); + + /*-------------------- + * AndroidMediaPlayer: M: + */ + void setDataSource(IMediaDataSource mediaDataSource); +} diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/ISurfaceTextureHolder.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/ISurfaceTextureHolder.java new file mode 100644 index 0000000..d62e9cb --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/ISurfaceTextureHolder.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2015 Zhang Rui + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tv.danmaku.ijk.media.player; + +import android.graphics.SurfaceTexture; + +public interface ISurfaceTextureHolder { + void setSurfaceTexture(SurfaceTexture surfaceTexture); + + SurfaceTexture getSurfaceTexture(); + + void setSurfaceTextureHost(ISurfaceTextureHost surfaceTextureHost); +} diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/ISurfaceTextureHost.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/ISurfaceTextureHost.java new file mode 100644 index 0000000..ff10c56 --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/ISurfaceTextureHost.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2015 Zhang Rui + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tv.danmaku.ijk.media.player; + +import android.graphics.SurfaceTexture; + +public interface ISurfaceTextureHost { + void releaseSurfaceTexture(SurfaceTexture surfaceTexture); +} diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkLibLoader.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkLibLoader.java new file mode 100644 index 0000000..f846fc6 --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkLibLoader.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2013-2014 Zhang Rui + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tv.danmaku.ijk.media.player; + +public interface IjkLibLoader { + void loadLibrary(String libName) throws UnsatisfiedLinkError, + SecurityException; +} diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaCodecInfo.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaCodecInfo.java new file mode 100644 index 0000000..3bec466 --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaCodecInfo.java @@ -0,0 +1,293 @@ +package tv.danmaku.ijk.media.player; + +import android.annotation.TargetApi; +import android.media.MediaCodecInfo; +import android.media.MediaCodecInfo.CodecCapabilities; +import android.media.MediaCodecInfo.CodecProfileLevel; +import android.os.Build; +import android.text.TextUtils; +import android.util.Log; + +import java.util.Locale; +import java.util.Map; +import java.util.TreeMap; + +public class IjkMediaCodecInfo { + private final static String TAG = "IjkMediaCodecInfo"; + + public static final int RANK_MAX = 1000; + public static final int RANK_TESTED = 800; + public static final int RANK_ACCEPTABLE = 700; + public static final int RANK_LAST_CHANCE = 600; + public static final int RANK_SECURE = 300; + public static final int RANK_SOFTWARE = 200; + public static final int RANK_NON_STANDARD = 100; + public static final int RANK_NO_SENSE = 0; + + public MediaCodecInfo mCodecInfo; + public int mRank = 0; + public String mMimeType; + + private static Map sKnownCodecList; + + private static synchronized Map getKnownCodecList() { + if (sKnownCodecList != null) + return sKnownCodecList; + + sKnownCodecList = new TreeMap( + String.CASE_INSENSITIVE_ORDER); + + // ----- Nvidia ----- + // Tegra3 + // Nexus 7 (2012) + // Tegra K1 + // Nexus 9 + sKnownCodecList.put("OMX.Nvidia.h264.decode", RANK_TESTED); + sKnownCodecList.put("OMX.Nvidia.h264.decode.secure", RANK_SECURE); + + // ----- Intel ----- + // Atom Z3735 + // Teclast X98 Air + sKnownCodecList.put("OMX.Intel.hw_vd.h264", RANK_TESTED + 1); + // Atom Z2560 + // Dell Venue 7 3730 + sKnownCodecList.put("OMX.Intel.VideoDecoder.AVC", RANK_TESTED); + + // ----- Qualcomm ----- + // MSM8260 + // Xiaomi MI 1S + sKnownCodecList.put("OMX.qcom.video.decoder.avc", RANK_TESTED); + sKnownCodecList.put("OMX.ittiam.video.decoder.avc", RANK_NO_SENSE); + + // ----- Samsung ----- + // Exynos 3110 + // Nexus S + sKnownCodecList.put("OMX.SEC.avc.dec", RANK_TESTED); + sKnownCodecList.put("OMX.SEC.AVC.Decoder", RANK_TESTED - 1); + // OMX.SEC.avcdec doesn't reorder output pictures on GT-9100 + sKnownCodecList.put("OMX.SEC.avcdec", RANK_TESTED - 2); + sKnownCodecList.put("OMX.SEC.avc.sw.dec", RANK_SOFTWARE); + // Exynos 5 ? + sKnownCodecList.put("OMX.Exynos.avc.dec", RANK_TESTED); + sKnownCodecList.put("OMX.Exynos.AVC.Decoder", RANK_TESTED - 1); + + // ------ Huawei hisilicon ------ + // Kirin 910, Mali 450 MP + // Huawei HONOR 3C (H30-L01) + sKnownCodecList.put("OMX.k3.video.decoder.avc", RANK_TESTED); + // Kirin 920, Mali T624 + // Huawei HONOR 6 + sKnownCodecList.put("OMX.IMG.MSVDX.Decoder.AVC", RANK_TESTED); + + // ----- TI ----- + // TI OMAP4460 + // Galaxy Nexus + sKnownCodecList.put("OMX.TI.DUCATI1.VIDEO.DECODER", RANK_TESTED); + + // ------ RockChip ------ + // Youku TVBox + sKnownCodecList.put("OMX.rk.video_decoder.avc", RANK_TESTED); + + // ------ AMLogic ----- + // MiBox1, 1s, 2 + sKnownCodecList.put("OMX.amlogic.avc.decoder.awesome", RANK_TESTED); + + // ------ Marvell ------ + // Lenovo A788t + sKnownCodecList.put("OMX.MARVELL.VIDEO.HW.CODA7542DECODER", RANK_TESTED); + sKnownCodecList.put("OMX.MARVELL.VIDEO.H264DECODER", RANK_SOFTWARE); + + // ----- TODO: need test ----- + sKnownCodecList.remove("OMX.Action.Video.Decoder"); + sKnownCodecList.remove("OMX.allwinner.video.decoder.avc"); + sKnownCodecList.remove("OMX.BRCM.vc4.decoder.avc"); + sKnownCodecList.remove("OMX.brcm.video.h264.hw.decoder"); + sKnownCodecList.remove("OMX.brcm.video.h264.decoder"); + sKnownCodecList.remove("OMX.cosmo.video.decoder.avc"); + sKnownCodecList.remove("OMX.duos.h264.decoder"); + sKnownCodecList.remove("OMX.hantro.81x0.video.decoder"); + sKnownCodecList.remove("OMX.hantro.G1.video.decoder"); + sKnownCodecList.remove("OMX.hisi.video.decoder"); + sKnownCodecList.remove("OMX.LG.decoder.video.avc"); + sKnownCodecList.remove("OMX.MS.AVC.Decoder"); + sKnownCodecList.remove("OMX.RENESAS.VIDEO.DECODER.H264"); + sKnownCodecList.remove("OMX.RTK.video.decoder"); + sKnownCodecList.remove("OMX.sprd.h264.decoder"); + sKnownCodecList.remove("OMX.ST.VFM.H264Dec"); + sKnownCodecList.remove("OMX.vpu.video_decoder.avc"); + sKnownCodecList.remove("OMX.WMT.decoder.avc"); + + // Really ? + sKnownCodecList.remove("OMX.bluestacks.hw.decoder"); + + // --------------- + // Useless codec + // ----- google ----- + sKnownCodecList.put("OMX.google.h264.decoder", RANK_SOFTWARE); + sKnownCodecList.put("OMX.google.h264.lc.decoder", RANK_SOFTWARE); + // ----- huawei k920 ----- + sKnownCodecList.put("OMX.k3.ffmpeg.decoder", RANK_SOFTWARE); + sKnownCodecList.put("OMX.ffmpeg.video.decoder", RANK_SOFTWARE); + // ----- unknown ----- + sKnownCodecList.put("OMX.sprd.soft.h264.decoder", RANK_SOFTWARE); + + return sKnownCodecList; + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + public static IjkMediaCodecInfo setupCandidate(MediaCodecInfo codecInfo, + String mimeType) { + if (codecInfo == null + || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) + return null; + + String name = codecInfo.getName(); + if (TextUtils.isEmpty(name)) + return null; + + name = name.toLowerCase(Locale.US); + int rank = RANK_NO_SENSE; + if (!name.startsWith("omx.")) { + rank = RANK_NON_STANDARD; + } else if (name.startsWith("omx.pv")) { + rank = RANK_SOFTWARE; + } else if (name.startsWith("omx.google.")) { + rank = RANK_SOFTWARE; + } else if (name.startsWith("omx.ffmpeg.")) { + rank = RANK_SOFTWARE; + } else if (name.startsWith("omx.k3.ffmpeg.")) { + rank = RANK_SOFTWARE; + } else if (name.startsWith("omx.avcodec.")) { + rank = RANK_SOFTWARE; + } else if (name.startsWith("omx.ittiam.")) { + // unknown codec in qualcomm SoC + rank = RANK_NO_SENSE; + } else if (name.startsWith("omx.mtk.")) { + // 1. MTK only works on 4.3 and above + // 2. MTK works on MIUI 6 (4.2.1) + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) + rank = RANK_NO_SENSE; + else + rank = RANK_TESTED; + } else { + Integer knownRank = getKnownCodecList().get(name); + if (knownRank != null) { + rank = knownRank; + } else { + try { + CodecCapabilities cap = codecInfo + .getCapabilitiesForType(mimeType); + if (cap != null) + rank = RANK_ACCEPTABLE; + else + rank = RANK_LAST_CHANCE; + } catch (Throwable e) { + rank = RANK_LAST_CHANCE; + } + } + } + + IjkMediaCodecInfo candidate = new IjkMediaCodecInfo(); + candidate.mCodecInfo = codecInfo; + candidate.mRank = rank; + candidate.mMimeType = mimeType; + return candidate; + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + public void dumpProfileLevels(String mimeType) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) + return; + + try { + CodecCapabilities caps = mCodecInfo + .getCapabilitiesForType(mimeType); + int maxProfile = 0; + int maxLevel = 0; + if (caps != null) { + if (caps.profileLevels != null) { + for (CodecProfileLevel profileLevel : caps.profileLevels) { + if (profileLevel == null) + continue; + + maxProfile = Math.max(maxProfile, profileLevel.profile); + maxLevel = Math.max(maxLevel, profileLevel.level); + } + } + } + + Log.i(TAG, + String.format(Locale.US, "%s", + getProfileLevelName(maxProfile, maxLevel))); + } catch (Throwable e) { + Log.i(TAG, "profile-level: exception"); + } + } + + public static String getProfileLevelName(int profile, int level) { + return String.format(Locale.US, " %s Profile Level %s (%d,%d)", + getProfileName(profile), getLevelName(level), profile, level); + } + + public static String getProfileName(int profile) { + switch (profile) { + case CodecProfileLevel.AVCProfileBaseline: + return "Baseline"; + case CodecProfileLevel.AVCProfileMain: + return "Main"; + case CodecProfileLevel.AVCProfileExtended: + return "Extends"; + case CodecProfileLevel.AVCProfileHigh: + return "High"; + case CodecProfileLevel.AVCProfileHigh10: + return "High10"; + case CodecProfileLevel.AVCProfileHigh422: + return "High422"; + case CodecProfileLevel.AVCProfileHigh444: + return "High444"; + default: + return "Unknown"; + } + } + + public static String getLevelName(int level) { + switch (level) { + case CodecProfileLevel.AVCLevel1: + return "1"; + case CodecProfileLevel.AVCLevel1b: + return "1b"; + case CodecProfileLevel.AVCLevel11: + return "11"; + case CodecProfileLevel.AVCLevel12: + return "12"; + case CodecProfileLevel.AVCLevel13: + return "13"; + case CodecProfileLevel.AVCLevel2: + return "2"; + case CodecProfileLevel.AVCLevel21: + return "21"; + case CodecProfileLevel.AVCLevel22: + return "22"; + case CodecProfileLevel.AVCLevel3: + return "3"; + case CodecProfileLevel.AVCLevel31: + return "31"; + case CodecProfileLevel.AVCLevel32: + return "32"; + case CodecProfileLevel.AVCLevel4: + return "4"; + case CodecProfileLevel.AVCLevel41: + return "41"; + case CodecProfileLevel.AVCLevel42: + return "42"; + case CodecProfileLevel.AVCLevel5: + return "5"; + case CodecProfileLevel.AVCLevel51: + return "51"; + case 65536: // CodecProfileLevel.AVCLevel52: + return "52"; + default: + return "0"; + } + } +} diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaMeta.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaMeta.java new file mode 100644 index 0000000..ef814f1 --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaMeta.java @@ -0,0 +1,380 @@ +package tv.danmaku.ijk.media.player; + +import android.os.Bundle; +import android.text.TextUtils; + +import java.util.ArrayList; +import java.util.Locale; + +@SuppressWarnings("SameParameterValue") +public class IjkMediaMeta { + // media meta + public static final String IJKM_KEY_FORMAT = "format"; + public static final String IJKM_KEY_DURATION_US = "duration_us"; + public static final String IJKM_KEY_START_US = "start_us"; + public static final String IJKM_KEY_BITRATE = "bitrate"; + public static final String IJKM_KEY_VIDEO_STREAM = "video"; + public static final String IJKM_KEY_AUDIO_STREAM = "audio"; + + // stream meta + public static final String IJKM_KEY_TYPE = "type"; + public static final String IJKM_VAL_TYPE__VIDEO = "video"; + public static final String IJKM_VAL_TYPE__AUDIO = "audio"; + public static final String IJKM_VAL_TYPE__UNKNOWN = "unknown"; + public static final String IJKM_KEY_LANGUAGE = "language"; + + public static final String IJKM_KEY_CODEC_NAME = "codec_name"; + public static final String IJKM_KEY_CODEC_PROFILE = "codec_profile"; + public static final String IJKM_KEY_CODEC_LEVEL = "codec_level"; + public static final String IJKM_KEY_CODEC_LONG_NAME = "codec_long_name"; + public static final String IJKM_KEY_CODEC_PIXEL_FORMAT = "codec_pixel_format"; + + // stream: video + public static final String IJKM_KEY_WIDTH = "width"; + public static final String IJKM_KEY_HEIGHT = "height"; + public static final String IJKM_KEY_FPS_NUM = "fps_num"; + public static final String IJKM_KEY_FPS_DEN = "fps_den"; + public static final String IJKM_KEY_TBR_NUM = "tbr_num"; + public static final String IJKM_KEY_TBR_DEN = "tbr_den"; + public static final String IJKM_KEY_SAR_NUM = "sar_num"; + public static final String IJKM_KEY_SAR_DEN = "sar_den"; + // stream: audio + public static final String IJKM_KEY_SAMPLE_RATE = "sample_rate"; + public static final String IJKM_KEY_CHANNEL_LAYOUT = "channel_layout"; + + public static final String IJKM_KEY_STREAMS = "streams"; + + public static final long AV_CH_FRONT_LEFT = 0x00000001; + public static final long AV_CH_FRONT_RIGHT = 0x00000002; + public static final long AV_CH_FRONT_CENTER = 0x00000004; + public static final long AV_CH_LOW_FREQUENCY = 0x00000008; + public static final long AV_CH_BACK_LEFT = 0x00000010; + public static final long AV_CH_BACK_RIGHT = 0x00000020; + public static final long AV_CH_FRONT_LEFT_OF_CENTER = 0x00000040; + public static final long AV_CH_FRONT_RIGHT_OF_CENTER = 0x00000080; + public static final long AV_CH_BACK_CENTER = 0x00000100; + public static final long AV_CH_SIDE_LEFT = 0x00000200; + public static final long AV_CH_SIDE_RIGHT = 0x00000400; + public static final long AV_CH_TOP_CENTER = 0x00000800; + public static final long AV_CH_TOP_FRONT_LEFT = 0x00001000; + public static final long AV_CH_TOP_FRONT_CENTER = 0x00002000; + public static final long AV_CH_TOP_FRONT_RIGHT = 0x00004000; + public static final long AV_CH_TOP_BACK_LEFT = 0x00008000; + public static final long AV_CH_TOP_BACK_CENTER = 0x00010000; + public static final long AV_CH_TOP_BACK_RIGHT = 0x00020000; + public static final long AV_CH_STEREO_LEFT = 0x20000000; + public static final long AV_CH_STEREO_RIGHT = 0x40000000; + public static final long AV_CH_WIDE_LEFT = 0x0000000080000000L; + public static final long AV_CH_WIDE_RIGHT = 0x0000000100000000L; + public static final long AV_CH_SURROUND_DIRECT_LEFT = 0x0000000200000000L; + public static final long AV_CH_SURROUND_DIRECT_RIGHT = 0x0000000400000000L; + public static final long AV_CH_LOW_FREQUENCY_2 = 0x0000000800000000L; + + public static final long AV_CH_LAYOUT_MONO = (AV_CH_FRONT_CENTER); + public static final long AV_CH_LAYOUT_STEREO = (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT); + public static final long AV_CH_LAYOUT_2POINT1 = (AV_CH_LAYOUT_STEREO | AV_CH_LOW_FREQUENCY); + public static final long AV_CH_LAYOUT_2_1 = (AV_CH_LAYOUT_STEREO | AV_CH_BACK_CENTER); + public static final long AV_CH_LAYOUT_SURROUND = (AV_CH_LAYOUT_STEREO | AV_CH_FRONT_CENTER); + public static final long AV_CH_LAYOUT_3POINT1 = (AV_CH_LAYOUT_SURROUND | AV_CH_LOW_FREQUENCY); + public static final long AV_CH_LAYOUT_4POINT0 = (AV_CH_LAYOUT_SURROUND | AV_CH_BACK_CENTER); + public static final long AV_CH_LAYOUT_4POINT1 = (AV_CH_LAYOUT_4POINT0 | AV_CH_LOW_FREQUENCY); + public static final long AV_CH_LAYOUT_2_2 = (AV_CH_LAYOUT_STEREO + | AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT); + public static final long AV_CH_LAYOUT_QUAD = (AV_CH_LAYOUT_STEREO + | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT); + public static final long AV_CH_LAYOUT_5POINT0 = (AV_CH_LAYOUT_SURROUND + | AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT); + public static final long AV_CH_LAYOUT_5POINT1 = (AV_CH_LAYOUT_5POINT0 | AV_CH_LOW_FREQUENCY); + public static final long AV_CH_LAYOUT_5POINT0_BACK = (AV_CH_LAYOUT_SURROUND + | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT); + public static final long AV_CH_LAYOUT_5POINT1_BACK = (AV_CH_LAYOUT_5POINT0_BACK | AV_CH_LOW_FREQUENCY); + public static final long AV_CH_LAYOUT_6POINT0 = (AV_CH_LAYOUT_5POINT0 | AV_CH_BACK_CENTER); + public static final long AV_CH_LAYOUT_6POINT0_FRONT = (AV_CH_LAYOUT_2_2 + | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER); + public static final long AV_CH_LAYOUT_HEXAGONAL = (AV_CH_LAYOUT_5POINT0_BACK | AV_CH_BACK_CENTER); + public static final long AV_CH_LAYOUT_6POINT1 = (AV_CH_LAYOUT_5POINT1 | AV_CH_BACK_CENTER); + public static final long AV_CH_LAYOUT_6POINT1_BACK = (AV_CH_LAYOUT_5POINT1_BACK | AV_CH_BACK_CENTER); + public static final long AV_CH_LAYOUT_6POINT1_FRONT = (AV_CH_LAYOUT_6POINT0_FRONT | AV_CH_LOW_FREQUENCY); + public static final long AV_CH_LAYOUT_7POINT0 = (AV_CH_LAYOUT_5POINT0 + | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT); + public static final long AV_CH_LAYOUT_7POINT0_FRONT = (AV_CH_LAYOUT_5POINT0 + | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER); + public static final long AV_CH_LAYOUT_7POINT1 = (AV_CH_LAYOUT_5POINT1 + | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT); + public static final long AV_CH_LAYOUT_7POINT1_WIDE = (AV_CH_LAYOUT_5POINT1 + | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER); + public static final long AV_CH_LAYOUT_7POINT1_WIDE_BACK = (AV_CH_LAYOUT_5POINT1_BACK + | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER); + public static final long AV_CH_LAYOUT_OCTAGONAL = (AV_CH_LAYOUT_5POINT0 + | AV_CH_BACK_LEFT | AV_CH_BACK_CENTER | AV_CH_BACK_RIGHT); + public static final long AV_CH_LAYOUT_STEREO_DOWNMIX = (AV_CH_STEREO_LEFT | AV_CH_STEREO_RIGHT); + + public Bundle mMediaMeta; + + public String mFormat; + public long mDurationUS; + public long mStartUS; + public long mBitrate; + + public final ArrayList mStreams = new ArrayList(); + public IjkStreamMeta mVideoStream; + public IjkStreamMeta mAudioStream; + + public String getString(String key) { + return mMediaMeta.getString(key); + } + + public int getInt(String key) { + return getInt(key, 0); + } + + public int getInt(String key, int defaultValue) { + String value = getString(key); + if (TextUtils.isEmpty(value)) + return defaultValue; + + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + public long getLong(String key) { + return getLong(key, 0); + } + + public long getLong(String key, long defaultValue) { + String value = getString(key); + if (TextUtils.isEmpty(value)) + return defaultValue; + + try { + return Long.parseLong(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + public ArrayList getParcelableArrayList(String key) { + return mMediaMeta.getParcelableArrayList(key); + } + + public String getDurationInline() { + long duration = mDurationUS + 5000; + long secs = duration / 1000000; + long mins = secs / 60; + secs %= 60; + long hours = mins / 60; + mins %= 60; + return String.format(Locale.US, "%02d:%02d:%02d", hours, mins, secs); + } + + public static IjkMediaMeta parse(Bundle mediaMeta) { + if (mediaMeta == null) + return null; + + IjkMediaMeta meta = new IjkMediaMeta(); + meta.mMediaMeta = mediaMeta; + + meta.mFormat = meta.getString(IJKM_KEY_FORMAT); + meta.mDurationUS = meta.getLong(IJKM_KEY_DURATION_US); + meta.mStartUS = meta.getLong(IJKM_KEY_START_US); + meta.mBitrate = meta.getLong(IJKM_KEY_BITRATE); + + int videoStreamIndex = meta.getInt(IJKM_KEY_VIDEO_STREAM, -1); + int audioStreamIndex = meta.getInt(IJKM_KEY_AUDIO_STREAM, -1); + + ArrayList streams = meta + .getParcelableArrayList(IJKM_KEY_STREAMS); + if (streams == null) + return meta; + + int index = -1; + for (Bundle streamBundle : streams) { + index++; + + if (streamBundle == null) { + continue; + } + + IjkStreamMeta streamMeta = new IjkStreamMeta(index); + streamMeta.mMeta = streamBundle; + streamMeta.mType = streamMeta.getString(IJKM_KEY_TYPE); + streamMeta.mLanguage = streamMeta.getString(IJKM_KEY_LANGUAGE); + if (TextUtils.isEmpty(streamMeta.mType)) + continue; + + streamMeta.mCodecName = streamMeta.getString(IJKM_KEY_CODEC_NAME); + streamMeta.mCodecProfile = streamMeta + .getString(IJKM_KEY_CODEC_PROFILE); + streamMeta.mCodecLongName = streamMeta + .getString(IJKM_KEY_CODEC_LONG_NAME); + streamMeta.mBitrate = streamMeta.getInt(IJKM_KEY_BITRATE); + + if (streamMeta.mType.equalsIgnoreCase(IJKM_VAL_TYPE__VIDEO)) { + streamMeta.mWidth = streamMeta.getInt(IJKM_KEY_WIDTH); + streamMeta.mHeight = streamMeta.getInt(IJKM_KEY_HEIGHT); + streamMeta.mFpsNum = streamMeta.getInt(IJKM_KEY_FPS_NUM); + streamMeta.mFpsDen = streamMeta.getInt(IJKM_KEY_FPS_DEN); + streamMeta.mTbrNum = streamMeta.getInt(IJKM_KEY_TBR_NUM); + streamMeta.mTbrDen = streamMeta.getInt(IJKM_KEY_TBR_DEN); + streamMeta.mSarNum = streamMeta.getInt(IJKM_KEY_SAR_NUM); + streamMeta.mSarDen = streamMeta.getInt(IJKM_KEY_SAR_DEN); + + if (videoStreamIndex == index) { + meta.mVideoStream = streamMeta; + } + } else if (streamMeta.mType.equalsIgnoreCase(IJKM_VAL_TYPE__AUDIO)) { + streamMeta.mSampleRate = streamMeta + .getInt(IJKM_KEY_SAMPLE_RATE); + streamMeta.mChannelLayout = streamMeta + .getLong(IJKM_KEY_CHANNEL_LAYOUT); + + if (audioStreamIndex == index) { + meta.mAudioStream = streamMeta; + } + } + meta.mStreams.add(streamMeta); + } + + return meta; + } + + public static class IjkStreamMeta { + public Bundle mMeta; + + public final int mIndex; + public String mType; + public String mLanguage; + + // common + public String mCodecName; + public String mCodecProfile; + public String mCodecLongName; + public long mBitrate; + + // video + public int mWidth; + public int mHeight; + public int mFpsNum; + public int mFpsDen; + public int mTbrNum; + public int mTbrDen; + public int mSarNum; + public int mSarDen; + + // audio + public int mSampleRate; + public long mChannelLayout; + + public IjkStreamMeta(int index) { + mIndex = index; + } + + public String getString(String key) { + return mMeta.getString(key); + } + + public int getInt(String key) { + return getInt(key, 0); + } + + public int getInt(String key, int defaultValue) { + String value = getString(key); + if (TextUtils.isEmpty(value)) + return defaultValue; + + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + public long getLong(String key) { + return getLong(key, 0); + } + + public long getLong(String key, long defaultValue) { + String value = getString(key); + if (TextUtils.isEmpty(value)) + return defaultValue; + + try { + return Long.parseLong(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + public String getCodecLongNameInline() { + if (!TextUtils.isEmpty(mCodecLongName)) { + return mCodecLongName; + } else if (!TextUtils.isEmpty(mCodecName)) { + return mCodecName; + } else { + return "N/A"; + } + } + + public String getCodecShortNameInline() { + if (!TextUtils.isEmpty(mCodecName)) { + return mCodecName; + } else { + return "N/A"; + } + } + + public String getResolutionInline() { + if (mWidth <= 0 || mHeight <= 0) { + return "N/A"; + } else if (mSarNum <= 0 || mSarDen <= 0) { + return String.format(Locale.US, "%d x %d", mWidth, mHeight); + } else { + return String.format(Locale.US, "%d x %d [SAR %d:%d]", mWidth, + mHeight, mSarNum, mSarDen); + } + } + + public String getFpsInline() { + if (mFpsNum <= 0 || mFpsDen <= 0) { + return "N/A"; + } else { + return String.valueOf(((float) (mFpsNum)) / mFpsDen); + } + } + + public String getBitrateInline() { + if (mBitrate <= 0) { + return "N/A"; + } else if (mBitrate < 1000) { + return String.format(Locale.US, "%d bit/s", mBitrate); + } else { + return String.format(Locale.US, "%d kb/s", mBitrate / 1000); + } + } + + public String getSampleRateInline() { + if (mSampleRate <= 0) { + return "N/A"; + } else { + return String.format(Locale.US, "%d Hz", mSampleRate); + } + } + + public String getChannelLayoutInline() { + if (mChannelLayout <= 0) { + return "N/A"; + } else { + if (mChannelLayout == AV_CH_LAYOUT_MONO) { + return "mono"; + } else if (mChannelLayout == AV_CH_LAYOUT_STEREO) { + return "stereo"; + } else { + return String.format(Locale.US, "%x", mChannelLayout); + } + } + } + } +} diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java new file mode 100644 index 0000000..0861533 --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java @@ -0,0 +1,1170 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * Copyright (C) 2013 Zhang Rui + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tv.danmaku.ijk.media.player; + +import android.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.content.ContentResolver; +import android.content.Context; +import android.content.res.AssetFileDescriptor; +import android.graphics.SurfaceTexture; +import android.media.MediaCodecInfo; +import android.media.MediaCodecList; +import android.media.RingtoneManager; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.ParcelFileDescriptor; +import android.os.PowerManager; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Log; +import android.view.Surface; +import android.view.SurfaceHolder; + +import java.io.FileDescriptor; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.security.InvalidParameterException; +import java.util.ArrayList; +import java.util.Locale; +import java.util.Map; + +import tv.danmaku.ijk.media.player.annotations.AccessedByNative; +import tv.danmaku.ijk.media.player.annotations.CalledByNative; +import tv.danmaku.ijk.media.player.misc.IMediaDataSource; +import tv.danmaku.ijk.media.player.misc.ITrackInfo; +import tv.danmaku.ijk.media.player.misc.IjkTrackInfo; +import tv.danmaku.ijk.media.player.pragma.DebugLog; + +/** + * @author bbcallen + * + * Java wrapper of ffplay. + */ +public final class IjkMediaPlayer extends AbstractMediaPlayer { + private final static String TAG = IjkMediaPlayer.class.getName(); + + private static final int MEDIA_NOP = 0; // interface test message + private static final int MEDIA_PREPARED = 1; + private static final int MEDIA_PLAYBACK_COMPLETE = 2; + private static final int MEDIA_BUFFERING_UPDATE = 3; + private static final int MEDIA_SEEK_COMPLETE = 4; + private static final int MEDIA_SET_VIDEO_SIZE = 5; + private static final int MEDIA_TIMED_TEXT = 99; + private static final int MEDIA_ERROR = 100; + private static final int MEDIA_INFO = 200; + + protected static final int MEDIA_SET_VIDEO_SAR = 10001; + + //---------------------------------------- + // options + public static final int IJK_LOG_UNKNOWN = 0; + public static final int IJK_LOG_DEFAULT = 1; + + public static final int IJK_LOG_VERBOSE = 2; + public static final int IJK_LOG_DEBUG = 3; + public static final int IJK_LOG_INFO = 4; + public static final int IJK_LOG_WARN = 5; + public static final int IJK_LOG_ERROR = 6; + public static final int IJK_LOG_FATAL = 7; + public static final int IJK_LOG_SILENT = 8; + + public static final int OPT_CATEGORY_FORMAT = 1; + public static final int OPT_CATEGORY_CODEC = 2; + public static final int OPT_CATEGORY_SWS = 3; + public static final int OPT_CATEGORY_PLAYER = 4; + + public static final int SDL_FCC_YV12 = 0x32315659; // YV12 + public static final int SDL_FCC_RV16 = 0x36315652; // RGB565 + public static final int SDL_FCC_RV32 = 0x32335652; // RGBX8888 + //---------------------------------------- + + //---------------------------------------- + // properties + public static final int PROP_FLOAT_VIDEO_DECODE_FRAMES_PER_SECOND = 10001; + public static final int PROP_FLOAT_VIDEO_OUTPUT_FRAMES_PER_SECOND = 10002; + public static final int FFP_PROP_FLOAT_PLAYBACK_RATE = 10003; + + public static final int FFP_PROP_INT64_SELECTED_VIDEO_STREAM = 20001; + public static final int FFP_PROP_INT64_SELECTED_AUDIO_STREAM = 20002; + + public static final int FFP_PROP_INT64_VIDEO_DECODER = 20003; + public static final int FFP_PROP_INT64_AUDIO_DECODER = 20004; + public static final int FFP_PROPV_DECODER_UNKNOWN = 0; + public static final int FFP_PROPV_DECODER_AVCODEC = 1; + public static final int FFP_PROPV_DECODER_MEDIACODEC = 2; + public static final int FFP_PROPV_DECODER_VIDEOTOOLBOX = 3; + public static final int FFP_PROP_INT64_VIDEO_CACHED_DURATION = 20005; + public static final int FFP_PROP_INT64_AUDIO_CACHED_DURATION = 20006; + public static final int FFP_PROP_INT64_VIDEO_CACHED_BYTES = 20007; + public static final int FFP_PROP_INT64_AUDIO_CACHED_BYTES = 20008; + public static final int FFP_PROP_INT64_VIDEO_CACHED_PACKETS = 20009; + public static final int FFP_PROP_INT64_AUDIO_CACHED_PACKETS = 20010; + //---------------------------------------- + + @AccessedByNative + private long mNativeMediaPlayer; + @AccessedByNative + private long mNativeMediaDataSource; + + @AccessedByNative + private int mNativeSurfaceTexture; + + @AccessedByNative + private int mListenerContext; + + private SurfaceHolder mSurfaceHolder; + private EventHandler mEventHandler; + private PowerManager.WakeLock mWakeLock = null; + private boolean mScreenOnWhilePlaying; + private boolean mStayAwake; + + private int mVideoWidth; + private int mVideoHeight; + private int mVideoSarNum; + private int mVideoSarDen; + + private String mDataSource; + + /** + * Default library loader + * Load them by yourself, if your libraries are not installed at default place. + */ + private static final IjkLibLoader sLocalLibLoader = new IjkLibLoader() { + @Override + public void loadLibrary(String libName) throws UnsatisfiedLinkError, SecurityException { + System.loadLibrary(libName); + } + }; + + private static volatile boolean mIsLibLoaded = false; + public static void loadLibrariesOnce(IjkLibLoader libLoader) { + synchronized (IjkMediaPlayer.class) { + if (!mIsLibLoaded) { + if (libLoader == null) + libLoader = sLocalLibLoader; + + libLoader.loadLibrary("ijkffmpeg"); + libLoader.loadLibrary("ijksdl"); + libLoader.loadLibrary("ijkplayer"); + mIsLibLoaded = true; + } + } + } + + private static volatile boolean mIsNativeInitialized = false; + private static void initNativeOnce() { + synchronized (IjkMediaPlayer.class) { + if (!mIsNativeInitialized) { + native_init(); + mIsNativeInitialized = true; + } + } + } + + /** + * Default constructor. Consider using one of the create() methods for + * synchronously instantiating a IjkMediaPlayer from a Uri or resource. + *

+ * When done with the IjkMediaPlayer, you should call {@link #release()}, to + * free the resources. If not released, too many IjkMediaPlayer instances + * may result in an exception. + *

+ */ + public IjkMediaPlayer() { + this(sLocalLibLoader); + } + + /** + * do not loadLibaray + * @param libLoader + * custom library loader, can be null. + */ + public IjkMediaPlayer(IjkLibLoader libLoader) { + initPlayer(libLoader); + } + + private void initPlayer(IjkLibLoader libLoader) { + loadLibrariesOnce(libLoader); + initNativeOnce(); + + Looper looper; + if ((looper = Looper.myLooper()) != null) { + mEventHandler = new EventHandler(this, looper); + } else if ((looper = Looper.getMainLooper()) != null) { + mEventHandler = new EventHandler(this, looper); + } else { + mEventHandler = null; + } + + /* + * Native setup requires a weak reference to our object. It's easier to + * create it here than in C++. + */ + native_setup(new WeakReference(this)); + } + + /* + * Update the IjkMediaPlayer SurfaceTexture. Call after setting a new + * display surface. + */ + private native void _setVideoSurface(Surface surface); + + /** + * Sets the {@link SurfaceHolder} to use for displaying the video portion of + * the media. + * + * Either a surface holder or surface must be set if a display or video sink + * is needed. Not calling this method or {@link #setSurface(Surface)} when + * playing back a video will result in only the audio track being played. A + * null surface holder or surface will result in only the audio track being + * played. + * + * @param sh + * the SurfaceHolder to use for video display + */ + @Override + public void setDisplay(SurfaceHolder sh) { + mSurfaceHolder = sh; + Surface surface; + if (sh != null) { + surface = sh.getSurface(); + } else { + surface = null; + } + _setVideoSurface(surface); + updateSurfaceScreenOn(); + } + + /** + * Sets the {@link Surface} to be used as the sink for the video portion of + * the media. This is similar to {@link #setDisplay(SurfaceHolder)}, but + * does not support {@link #setScreenOnWhilePlaying(boolean)}. Setting a + * Surface will un-set any Surface or SurfaceHolder that was previously set. + * A null surface will result in only the audio track being played. + * + * If the Surface sends frames to a {@link SurfaceTexture}, the timestamps + * returned from {@link SurfaceTexture#getTimestamp()} will have an + * unspecified zero point. These timestamps cannot be directly compared + * between different media sources, different instances of the same media + * source, or multiple runs of the same program. The timestamp is normally + * monotonically increasing and is unaffected by time-of-day adjustments, + * but it is reset when the position is set. + * + * @param surface + * The {@link Surface} to be used for the video portion of the + * media. + */ + @Override + public void setSurface(Surface surface) { + if (mScreenOnWhilePlaying && surface != null) { + DebugLog.w(TAG, + "setScreenOnWhilePlaying(true) is ineffective for Surface"); + } + mSurfaceHolder = null; + _setVideoSurface(surface); + updateSurfaceScreenOn(); + } + + /** + * Sets the data source as a content Uri. + * + * @param context the Context to use when resolving the Uri + * @param uri the Content URI of the data you want to play + * @throws IllegalStateException if it is called in an invalid state + */ + @Override + public void setDataSource(Context context, Uri uri) + throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { + setDataSource(context, uri, null); + } + + /** + * Sets the data source as a content Uri. + * + * @param context the Context to use when resolving the Uri + * @param uri the Content URI of the data you want to play + * @param headers the headers to be sent together with the request for the data + * Note that the cross domain redirection is allowed by default, but that can be + * changed with key/value pairs through the headers parameter with + * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value + * to disallow or allow cross domain redirection. + * @throws IllegalStateException if it is called in an invalid state + */ + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) + @Override + public void setDataSource(Context context, Uri uri, Map headers) + throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { + final String scheme = uri.getScheme(); + if (ContentResolver.SCHEME_FILE.equals(scheme)) { + setDataSource(uri.getPath()); + return; + } else if (ContentResolver.SCHEME_CONTENT.equals(scheme) + && Settings.AUTHORITY.equals(uri.getAuthority())) { + // Redirect ringtones to go directly to underlying provider + uri = RingtoneManager.getActualDefaultRingtoneUri(context, + RingtoneManager.getDefaultType(uri)); + if (uri == null) { + throw new FileNotFoundException("Failed to resolve default ringtone"); + } + } + + AssetFileDescriptor fd = null; + try { + ContentResolver resolver = context.getContentResolver(); + fd = resolver.openAssetFileDescriptor(uri, "r"); + if (fd == null) { + return; + } + // Note: using getDeclaredLength so that our behavior is the same + // as previous versions when the content provider is returning + // a full file. + if (fd.getDeclaredLength() < 0) { + setDataSource(fd.getFileDescriptor()); + } else { + setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getDeclaredLength()); + } + return; + } catch (SecurityException ignored) { + } catch (IOException ignored) { + } finally { + if (fd != null) { + fd.close(); + } + } + + Log.d(TAG, "Couldn't open file on client side, trying server side"); + + setDataSource(uri.toString(), headers); + } + + /** + * Sets the data source (file-path or http/rtsp URL) to use. + * + * @param path + * the path of the file, or the http/rtsp URL of the stream you + * want to play + * @throws IllegalStateException + * if it is called in an invalid state + * + *

+ * When path refers to a local file, the file may + * actually be opened by a process other than the calling + * application. This implies that the pathname should be an + * absolute path (as any other process runs with unspecified + * current working directory), and that the pathname should + * reference a world-readable file. + */ + @Override + public void setDataSource(String path) + throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { + mDataSource = path; + _setDataSource(path, null, null); + } + + /** + * Sets the data source (file-path or http/rtsp URL) to use. + * + * @param path the path of the file, or the http/rtsp URL of the stream you want to play + * @param headers the headers associated with the http request for the stream you want to play + * @throws IllegalStateException if it is called in an invalid state + */ + public void setDataSource(String path, Map headers) + throws IOException, IllegalArgumentException, SecurityException, IllegalStateException + { + if (headers != null && !headers.isEmpty()) { + StringBuilder sb = new StringBuilder(); + for(Map.Entry entry: headers.entrySet()) { + sb.append(entry.getKey()); + sb.append(":"); + String value = entry.getValue(); + if (!TextUtils.isEmpty(value)) + sb.append(entry.getValue()); + sb.append("\r\n"); + setOption(OPT_CATEGORY_FORMAT, "headers", sb.toString()); + } + } + setDataSource(path); + } + + /** + * Sets the data source (FileDescriptor) to use. It is the caller's responsibility + * to close the file descriptor. It is safe to do so as soon as this call returns. + * + * @param fd the FileDescriptor for the file you want to play + * @throws IllegalStateException if it is called in an invalid state + */ + @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) + @Override + public void setDataSource(FileDescriptor fd) + throws IOException, IllegalArgumentException, IllegalStateException { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR1) { + int native_fd = -1; + try { + Field f = fd.getClass().getDeclaredField("descriptor"); //NoSuchFieldException + f.setAccessible(true); + native_fd = f.getInt(fd); //IllegalAccessException + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + _setDataSourceFd(native_fd); + } else { + ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(fd); + try { + _setDataSourceFd(pfd.getFd()); + } finally { + pfd.close(); + } + } + } + + /** + * Sets the data source (FileDescriptor) to use. The FileDescriptor must be + * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility + * to close the file descriptor. It is safe to do so as soon as this call returns. + * + * @param fd the FileDescriptor for the file you want to play + * @param offset the offset into the file where the data to be played starts, in bytes + * @param length the length in bytes of the data to be played + * @throws IllegalStateException if it is called in an invalid state + */ + private void setDataSource(FileDescriptor fd, long offset, long length) + throws IOException, IllegalArgumentException, IllegalStateException { + // FIXME: handle offset, length + setDataSource(fd); + } + + public void setDataSource(IMediaDataSource mediaDataSource) + throws IllegalArgumentException, SecurityException, IllegalStateException { + _setDataSource(mediaDataSource); + } + + private native void _setDataSource(String path, String[] keys, String[] values) + throws IOException, IllegalArgumentException, SecurityException, IllegalStateException; + + private native void _setDataSourceFd(int fd) + throws IOException, IllegalArgumentException, SecurityException, IllegalStateException; + + private native void _setDataSource(IMediaDataSource mediaDataSource) + throws IllegalArgumentException, SecurityException, IllegalStateException; + + @Override + public String getDataSource() { + return mDataSource; + } + + @Override + public void prepareAsync() throws IllegalStateException { + _prepareAsync(); + } + + public native void _prepareAsync() throws IllegalStateException; + + @Override + public void start() throws IllegalStateException { + stayAwake(true); + _start(); + } + + private native void _start() throws IllegalStateException; + + @Override + public void stop() throws IllegalStateException { + stayAwake(false); + _stop(); + } + + private native void _stop() throws IllegalStateException; + + @Override + public void pause() throws IllegalStateException { + stayAwake(false); + _pause(); + } + + private native void _pause() throws IllegalStateException; + + @SuppressLint("Wakelock") + @Override + public void setWakeMode(Context context, int mode) { + boolean washeld = false; + if (mWakeLock != null) { + if (mWakeLock.isHeld()) { + washeld = true; + mWakeLock.release(); + } + mWakeLock = null; + } + + PowerManager pm = (PowerManager) context + .getSystemService(Context.POWER_SERVICE); + mWakeLock = pm.newWakeLock(mode | PowerManager.ON_AFTER_RELEASE, + IjkMediaPlayer.class.getName()); + mWakeLock.setReferenceCounted(false); + if (washeld) { + mWakeLock.acquire(); + } + } + + @Override + public void setScreenOnWhilePlaying(boolean screenOn) { + if (mScreenOnWhilePlaying != screenOn) { + if (screenOn && mSurfaceHolder == null) { + DebugLog.w(TAG, + "setScreenOnWhilePlaying(true) is ineffective without a SurfaceHolder"); + } + mScreenOnWhilePlaying = screenOn; + updateSurfaceScreenOn(); + } + } + + @SuppressLint("Wakelock") + private void stayAwake(boolean awake) { + if (mWakeLock != null) { + if (awake && !mWakeLock.isHeld()) { + mWakeLock.acquire(); + } else if (!awake && mWakeLock.isHeld()) { + mWakeLock.release(); + } + } + mStayAwake = awake; + updateSurfaceScreenOn(); + } + + private void updateSurfaceScreenOn() { + if (mSurfaceHolder != null) { + mSurfaceHolder.setKeepScreenOn(mScreenOnWhilePlaying && mStayAwake); + } + } + + @Override + public IjkTrackInfo[] getTrackInfo() { + Bundle bundle = getMediaMeta(); + if (bundle == null) + return null; + + IjkMediaMeta mediaMeta = IjkMediaMeta.parse(bundle); + if (mediaMeta == null || mediaMeta.mStreams == null) + return null; + + ArrayList trackInfos = new ArrayList(); + for (IjkMediaMeta.IjkStreamMeta streamMeta: mediaMeta.mStreams) { + IjkTrackInfo trackInfo = new IjkTrackInfo(streamMeta); + if (streamMeta.mType.equalsIgnoreCase(IjkMediaMeta.IJKM_VAL_TYPE__VIDEO)) { + trackInfo.setTrackType(ITrackInfo.MEDIA_TRACK_TYPE_VIDEO); + } else if (streamMeta.mType.equalsIgnoreCase(IjkMediaMeta.IJKM_VAL_TYPE__AUDIO)) { + trackInfo.setTrackType(ITrackInfo.MEDIA_TRACK_TYPE_AUDIO); + } + trackInfos.add(trackInfo); + } + + return trackInfos.toArray(new IjkTrackInfo[trackInfos.size()]); + } + + // TODO: @Override + public int getSelectedTrack(int trackType) { + switch (trackType) { + case ITrackInfo.MEDIA_TRACK_TYPE_VIDEO: + return (int)_getPropertyLong(FFP_PROP_INT64_SELECTED_VIDEO_STREAM, -1); + case ITrackInfo.MEDIA_TRACK_TYPE_AUDIO: + return (int)_getPropertyLong(FFP_PROP_INT64_SELECTED_AUDIO_STREAM, -1); + default: + return -1; + } + } + + // experimental, should set DEFAULT_MIN_FRAMES and MAX_MIN_FRAMES to 25 + // TODO: @Override + public void selectTrack(int track) { + _setStreamSelected(track, true); + } + + // experimental, should set DEFAULT_MIN_FRAMES and MAX_MIN_FRAMES to 25 + // TODO: @Override + public void deselectTrack(int track) { + _setStreamSelected(track, false); + } + + private native void _setStreamSelected(int stream, boolean select); + + @Override + public int getVideoWidth() { + return mVideoWidth; + } + + @Override + public int getVideoHeight() { + return mVideoHeight; + } + + @Override + public int getVideoSarNum() { + return mVideoSarNum; + } + + @Override + public int getVideoSarDen() { + return mVideoSarDen; + } + + @Override + public native boolean isPlaying(); + + @Override + public native void seekTo(long msec) throws IllegalStateException; + + @Override + public native long getCurrentPosition(); + + @Override + public native long getDuration(); + + /** + * Releases resources associated with this IjkMediaPlayer object. It is + * considered good practice to call this method when you're done using the + * IjkMediaPlayer. In particular, whenever an Activity of an application is + * paused (its onPause() method is called), or stopped (its onStop() method + * is called), this method should be invoked to release the IjkMediaPlayer + * object, unless the application has a special need to keep the object + * around. In addition to unnecessary resources (such as memory and + * instances of codecs) being held, failure to call this method immediately + * if a IjkMediaPlayer object is no longer needed may also lead to + * continuous battery consumption for mobile devices, and playback failure + * for other applications if no multiple instances of the same codec are + * supported on a device. Even if multiple instances of the same codec are + * supported, some performance degradation may be expected when unnecessary + * multiple instances are used at the same time. + */ + @Override + public void release() { + stayAwake(false); + updateSurfaceScreenOn(); + resetListeners(); + _release(); + } + + private native void _release(); + + @Override + public void reset() { + stayAwake(false); + _reset(); + // make sure none of the listeners get called anymore + mEventHandler.removeCallbacksAndMessages(null); + + mVideoWidth = 0; + mVideoHeight = 0; + } + + private native void _reset(); + + /** + * Sets the player to be looping or non-looping. + * + * @param looping whether to loop or not + */ + @Override + public void setLooping(boolean looping) { + int loopCount = looping ? 0 : 1; + setOption(OPT_CATEGORY_PLAYER, "loop", loopCount); + _setLoopCount(loopCount); + } + + private native void _setLoopCount(int loopCount); + + /** + * Checks whether the MediaPlayer is looping or non-looping. + * + * @return true if the MediaPlayer is currently looping, false otherwise + */ + @Override + public boolean isLooping() { + int loopCount = _getLoopCount(); + return loopCount != 1; + } + + private native int _getLoopCount(); + + @TargetApi(Build.VERSION_CODES.M) + public void setSpeed(float speed) { + _setPropertyFloat(FFP_PROP_FLOAT_PLAYBACK_RATE, speed); + } + + @TargetApi(Build.VERSION_CODES.M) + public float getSpeed(float speed) { + return _getPropertyFloat(FFP_PROP_FLOAT_PLAYBACK_RATE, .0f); + } + + public int getVideoDecoder() { + return (int)_getPropertyLong(FFP_PROP_INT64_VIDEO_DECODER, FFP_PROPV_DECODER_UNKNOWN); + } + + public float getVideoOutputFramesPerSecond() { + return _getPropertyFloat(PROP_FLOAT_VIDEO_OUTPUT_FRAMES_PER_SECOND, 0.0f); + } + + public float getVideoDecodeFramesPerSecond() { + return _getPropertyFloat(PROP_FLOAT_VIDEO_DECODE_FRAMES_PER_SECOND, 0.0f); + } + + public long getVideoCachedDuration() { + return _getPropertyLong(FFP_PROP_INT64_VIDEO_CACHED_DURATION, 0); + } + + public long getAudioCachedDuration() { + return _getPropertyLong(FFP_PROP_INT64_AUDIO_CACHED_DURATION, 0); + } + + public long getVideoCachedBytes() { + return _getPropertyLong(FFP_PROP_INT64_VIDEO_CACHED_BYTES, 0); + } + + public long getAudioCachedBytes() { + return _getPropertyLong(FFP_PROP_INT64_AUDIO_CACHED_BYTES, 0); + } + + public long getVideoCachedPackets() { + return _getPropertyLong(FFP_PROP_INT64_VIDEO_CACHED_PACKETS, 0); + } + + public long getAudioCachedPackets() { + return _getPropertyLong(FFP_PROP_INT64_AUDIO_CACHED_PACKETS, 0); + } + + private native float _getPropertyFloat(int property, float defaultValue); + private native void _setPropertyFloat(int property, float value); + private native long _getPropertyLong(int property, long defaultValue); + private native void _setPropertyLong(int property, long value); + + @Override + public native void setVolume(float leftVolume, float rightVolume); + + @Override + public native int getAudioSessionId(); + + @Override + public MediaInfo getMediaInfo() { + MediaInfo mediaInfo = new MediaInfo(); + mediaInfo.mMediaPlayerName = "ijkplayer"; + + String videoCodecInfo = _getVideoCodecInfo(); + if (!TextUtils.isEmpty(videoCodecInfo)) { + String nodes[] = videoCodecInfo.split(","); + if (nodes.length >= 2) { + mediaInfo.mVideoDecoder = nodes[0]; + mediaInfo.mVideoDecoderImpl = nodes[1]; + } else if (nodes.length >= 1) { + mediaInfo.mVideoDecoder = nodes[0]; + mediaInfo.mVideoDecoderImpl = ""; + } + } + + String audioCodecInfo = _getAudioCodecInfo(); + if (!TextUtils.isEmpty(audioCodecInfo)) { + String nodes[] = audioCodecInfo.split(","); + if (nodes.length >= 2) { + mediaInfo.mAudioDecoder = nodes[0]; + mediaInfo.mAudioDecoderImpl = nodes[1]; + } else if (nodes.length >= 1) { + mediaInfo.mAudioDecoder = nodes[0]; + mediaInfo.mAudioDecoderImpl = ""; + } + } + + try { + mediaInfo.mMeta = IjkMediaMeta.parse(_getMediaMeta()); + } catch (Throwable e) { + e.printStackTrace(); + } + return mediaInfo; + } + + @Override + public void setLogEnabled(boolean enable) { + // do nothing + } + + @Override + public boolean isPlayable() { + return true; + } + + private native String _getVideoCodecInfo(); + private native String _getAudioCodecInfo(); + + public void setOption(int category, String name, String value) + { + _setOption(category, name, value); + } + + public void setOption(int category, String name, long value) + { + _setOption(category, name, value); + } + + private native void _setOption(int category, String name, String value); + private native void _setOption(int category, String name, long value); + + public Bundle getMediaMeta() { + return _getMediaMeta(); + } + private native Bundle _getMediaMeta(); + + public static String getColorFormatName(int mediaCodecColorFormat) { + return _getColorFormatName(mediaCodecColorFormat); + } + + private static native String _getColorFormatName(int mediaCodecColorFormat); + + @Override + public void setAudioStreamType(int streamtype) { + // do nothing + } + + @Override + public void setKeepInBackground(boolean keepInBackground) { + // do nothing + } + + private static native void native_init(); + + private native void native_setup(Object IjkMediaPlayer_this); + + private native void native_finalize(); + + private native void native_message_loop(Object IjkMediaPlayer_this); + + protected void finalize() throws Throwable { + super.finalize(); + native_finalize(); + } + + private static class EventHandler extends Handler { + private final WeakReference mWeakPlayer; + + public EventHandler(IjkMediaPlayer mp, Looper looper) { + super(looper); + mWeakPlayer = new WeakReference(mp); + } + + @Override + public void handleMessage(Message msg) { + IjkMediaPlayer player = mWeakPlayer.get(); + if (player == null || player.mNativeMediaPlayer == 0) { + DebugLog.w(TAG, + "IjkMediaPlayer went away with unhandled events"); + return; + } + + switch (msg.what) { + case MEDIA_PREPARED: + player.notifyOnPrepared(); + return; + + case MEDIA_PLAYBACK_COMPLETE: + player.stayAwake(false); + player.notifyOnCompletion(); + return; + + case MEDIA_BUFFERING_UPDATE: + long bufferPosition = msg.arg1; + if (bufferPosition < 0) { + bufferPosition = 0; + } + + long percent = 0; + long duration = player.getDuration(); + if (duration > 0) { + percent = bufferPosition * 100 / duration; + } + if (percent >= 100) { + percent = 100; + } + + // DebugLog.efmt(TAG, "Buffer (%d%%) %d/%d", percent, bufferPosition, duration); + player.notifyOnBufferingUpdate((int)percent); + return; + + case MEDIA_SEEK_COMPLETE: + player.notifyOnSeekComplete(); + return; + + case MEDIA_SET_VIDEO_SIZE: + player.mVideoWidth = msg.arg1; + player.mVideoHeight = msg.arg2; + player.notifyOnVideoSizeChanged(player.mVideoWidth, player.mVideoHeight, + player.mVideoSarNum, player.mVideoSarDen); + return; + + case MEDIA_ERROR: + DebugLog.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")"); + if (!player.notifyOnError(msg.arg1, msg.arg2)) { + player.notifyOnCompletion(); + } + player.stayAwake(false); + return; + + case MEDIA_INFO: + switch (msg.arg1) { + case MEDIA_INFO_VIDEO_RENDERING_START: + DebugLog.i(TAG, "Info: MEDIA_INFO_VIDEO_RENDERING_START\n"); + break; + } + player.notifyOnInfo(msg.arg1, msg.arg2); + // No real default action so far. + return; + case MEDIA_TIMED_TEXT: + // do nothing + break; + + case MEDIA_NOP: // interface test message - ignore + break; + + case MEDIA_SET_VIDEO_SAR: + player.mVideoSarNum = msg.arg1; + player.mVideoSarDen = msg.arg2; + player.notifyOnVideoSizeChanged(player.mVideoWidth, player.mVideoHeight, + player.mVideoSarNum, player.mVideoSarDen); + break; + + default: + DebugLog.e(TAG, "Unknown message type " + msg.what); + } + } + } + + /* + * Called from native code when an interesting event happens. This method + * just uses the EventHandler system to post the event back to the main app + * thread. We use a weak reference to the original IjkMediaPlayer object so + * that the native code is safe from the object disappearing from underneath + * it. (This is the cookie passed to native_setup().) + */ + @CalledByNative + private static void postEventFromNative(Object weakThiz, int what, + int arg1, int arg2, Object obj) { + if (weakThiz == null) + return; + + @SuppressWarnings("rawtypes") + IjkMediaPlayer mp = (IjkMediaPlayer) ((WeakReference) weakThiz).get(); + if (mp == null) { + return; + } + + if (what == MEDIA_INFO && arg1 == MEDIA_INFO_STARTED_AS_NEXT) { + // this acquires the wakelock if needed, and sets the client side + // state + mp.start(); + } + if (mp.mEventHandler != null) { + Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj); + mp.mEventHandler.sendMessage(m); + } + } + + /* + * ControlMessage + */ + + private OnControlMessageListener mOnControlMessageListener; + public void setOnControlMessageListener(OnControlMessageListener listener) { + mOnControlMessageListener = listener; + } + + public interface OnControlMessageListener { + String onControlResolveSegmentUrl(int segment); + } + + /* + * NativeInvoke + */ + + private OnNativeInvokeListener mOnNativeInvokeListener; + public void setOnNativeInvokeListener(OnNativeInvokeListener listener) { + mOnNativeInvokeListener = listener; + } + + public interface OnNativeInvokeListener { + int ON_CONCAT_RESOLVE_SEGMENT = 0x10000; + int ON_TCP_OPEN = 0x10001; + int ON_HTTP_OPEN = 0x10002; + // int ON_HTTP_RETRY = 0x10003; + int ON_LIVE_RETRY = 0x10004; + + String ARG_URL = "url"; + String ARG_SEGMENT_INDEX = "segment_index"; + String ARG_RETRY_COUNTER = "retry_counter"; + + /* + * @return true if invoke is handled + * @throws Exception on any error + */ + boolean onNativeInvoke(int what, Bundle args); + } + + @CalledByNative + private static boolean onNativeInvoke(Object weakThiz, int what, Bundle args) { + DebugLog.ifmt(TAG, "onNativeInvoke %d", what); + if (weakThiz == null || !(weakThiz instanceof WeakReference)) + throw new IllegalStateException(".onNativeInvoke()"); + + @SuppressWarnings("unchecked") + WeakReference weakPlayer = (WeakReference) weakThiz; + IjkMediaPlayer player = weakPlayer.get(); + if (player == null) + throw new IllegalStateException(".onNativeInvoke()"); + + OnNativeInvokeListener listener = player.mOnNativeInvokeListener; + if (listener != null && listener.onNativeInvoke(what, args)) + return true; + + switch (what) { + case OnNativeInvokeListener.ON_CONCAT_RESOLVE_SEGMENT: { + OnControlMessageListener onControlMessageListener = player.mOnControlMessageListener; + if (onControlMessageListener == null) + return false; + + int segmentIndex = args.getInt(OnNativeInvokeListener.ARG_SEGMENT_INDEX, -1); + if (segmentIndex < 0) + throw new InvalidParameterException("onNativeInvoke(invalid segment index)"); + + String newUrl = onControlMessageListener.onControlResolveSegmentUrl(segmentIndex); + if (newUrl == null) + throw new RuntimeException(new IOException("onNativeInvoke() = ")); + + args.putString(OnNativeInvokeListener.ARG_URL, newUrl); + return true; + } + default: + return false; + } + } + + /* + * MediaCodec select + */ + + public interface OnMediaCodecSelectListener { + String onMediaCodecSelect(IMediaPlayer mp, String mimeType, int profile, int level); + } + private OnMediaCodecSelectListener mOnMediaCodecSelectListener; + public void setOnMediaCodecSelectListener(OnMediaCodecSelectListener listener) { + mOnMediaCodecSelectListener = listener; + } + + public void resetListeners() { + super.resetListeners(); + mOnMediaCodecSelectListener = null; + } + + @CalledByNative + private static String onSelectCodec(Object weakThiz, String mimeType, int profile, int level) { + if (weakThiz == null || !(weakThiz instanceof WeakReference)) + return null; + + @SuppressWarnings("unchecked") + WeakReference weakPlayer = (WeakReference) weakThiz; + IjkMediaPlayer player = weakPlayer.get(); + if (player == null) + return null; + + OnMediaCodecSelectListener listener = player.mOnMediaCodecSelectListener; + if (listener == null) + listener = DefaultMediaCodecSelector.sInstance; + + return listener.onMediaCodecSelect(player, mimeType, profile, level); + } + + public static class DefaultMediaCodecSelector implements OnMediaCodecSelectListener { + public static final DefaultMediaCodecSelector sInstance = new DefaultMediaCodecSelector(); + + @SuppressWarnings("deprecation") + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + public String onMediaCodecSelect(IMediaPlayer mp, String mimeType, int profile, int level) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) + return null; + + if (TextUtils.isEmpty(mimeType)) + return null; + + Log.i(TAG, String.format(Locale.US, "onSelectCodec: mime=%s, profile=%d, level=%d", mimeType, profile, level)); + ArrayList candidateCodecList = new ArrayList(); + int numCodecs = MediaCodecList.getCodecCount(); + for (int i = 0; i < numCodecs; i++) { + MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i); + Log.d(TAG, String.format(Locale.US, " found codec: %s", codecInfo.getName())); + if (codecInfo.isEncoder()) + continue; + + String[] types = codecInfo.getSupportedTypes(); + if (types == null) + continue; + + for(String type: types) { + if (TextUtils.isEmpty(type)) + continue; + + Log.d(TAG, String.format(Locale.US, " mime: %s", type)); + if (!type.equalsIgnoreCase(mimeType)) + continue; + + IjkMediaCodecInfo candidate = IjkMediaCodecInfo.setupCandidate(codecInfo, mimeType); + if (candidate == null) + continue; + + candidateCodecList.add(candidate); + Log.i(TAG, String.format(Locale.US, "candidate codec: %s rank=%d", codecInfo.getName(), candidate.mRank)); + candidate.dumpProfileLevels(mimeType); + } + } + + if (candidateCodecList.isEmpty()) { + return null; + } + + IjkMediaCodecInfo bestCodec = candidateCodecList.get(0); + + for (IjkMediaCodecInfo codec : candidateCodecList) { + if (codec.mRank > bestCodec.mRank) { + bestCodec = codec; + } + } + + if (bestCodec.mRank < IjkMediaCodecInfo.RANK_LAST_CHANCE) { + Log.w(TAG, String.format(Locale.US, "unaccetable codec: %s", bestCodec.mCodecInfo.getName())); + return null; + } + + Log.i(TAG, String.format(Locale.US, "selected codec: %s rank=%d", bestCodec.mCodecInfo.getName(), bestCodec.mRank)); + return bestCodec.mCodecInfo.getName(); + } + } + + public static native void native_profileBegin(String libName); + public static native void native_profileEnd(); + public static native void native_setLogLevel(int level); +} diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/MediaInfo.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/MediaInfo.java new file mode 100644 index 0000000..6cd5004 --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/MediaInfo.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2013-2014 Zhang Rui + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tv.danmaku.ijk.media.player; + +public class MediaInfo { + public String mMediaPlayerName; + + public String mVideoDecoder; + public String mVideoDecoderImpl; + + public String mAudioDecoder; + public String mAudioDecoderImpl; + + public IjkMediaMeta mMeta; +} diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/MediaPlayerProxy.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/MediaPlayerProxy.java new file mode 100644 index 0000000..3dfbb1a --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/MediaPlayerProxy.java @@ -0,0 +1,323 @@ +/* + * Copyright (C) 2015 Zhang Rui + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tv.danmaku.ijk.media.player; + +import android.annotation.TargetApi; +import android.content.Context; +import android.net.Uri; +import android.os.Build; +import android.view.Surface; +import android.view.SurfaceHolder; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.util.Map; + +import tv.danmaku.ijk.media.player.misc.IMediaDataSource; +import tv.danmaku.ijk.media.player.misc.ITrackInfo; + +public class MediaPlayerProxy implements IMediaPlayer { + protected final IMediaPlayer mBackEndMediaPlayer; + + public MediaPlayerProxy(IMediaPlayer backEndMediaPlayer) { + mBackEndMediaPlayer = backEndMediaPlayer; + } + + public IMediaPlayer getInternalMediaPlayer() { + return mBackEndMediaPlayer; + } + + @Override + public void setDisplay(SurfaceHolder sh) { + mBackEndMediaPlayer.setDisplay(sh); + } + + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) + @Override + public void setSurface(Surface surface) { + mBackEndMediaPlayer.setSurface(surface); + } + + @Override + public void setDataSource(Context context, Uri uri) + throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { + mBackEndMediaPlayer.setDataSource(context, uri); + } + + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) + @Override + public void setDataSource(Context context, Uri uri, Map headers) + throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { + mBackEndMediaPlayer.setDataSource(context, uri, headers); + } + + @Override + public void setDataSource(FileDescriptor fd) + throws IOException, IllegalArgumentException, IllegalStateException { + mBackEndMediaPlayer.setDataSource(fd); + } + + @Override + public void setDataSource(String path) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { + mBackEndMediaPlayer.setDataSource(path); + } + + @Override + public void setDataSource(IMediaDataSource mediaDataSource) { + mBackEndMediaPlayer.setDataSource(mediaDataSource); + } + + @Override + public String getDataSource() { + return mBackEndMediaPlayer.getDataSource(); + } + + @Override + public void prepareAsync() throws IllegalStateException { + mBackEndMediaPlayer.prepareAsync(); + } + + @Override + public void start() throws IllegalStateException { + mBackEndMediaPlayer.start(); + } + + @Override + public void stop() throws IllegalStateException { + mBackEndMediaPlayer.stop(); + } + + @Override + public void pause() throws IllegalStateException { + mBackEndMediaPlayer.pause(); + } + + @Override + public void setScreenOnWhilePlaying(boolean screenOn) { + mBackEndMediaPlayer.setScreenOnWhilePlaying(screenOn); + } + + @Override + public int getVideoWidth() { + return mBackEndMediaPlayer.getVideoWidth(); + } + + @Override + public int getVideoHeight() { + return mBackEndMediaPlayer.getVideoHeight(); + } + + @Override + public boolean isPlaying() { + return mBackEndMediaPlayer.isPlaying(); + } + + @Override + public void seekTo(long msec) throws IllegalStateException { + mBackEndMediaPlayer.seekTo(msec); + } + + @Override + public long getCurrentPosition() { + return mBackEndMediaPlayer.getCurrentPosition(); + } + + @Override + public long getDuration() { + return mBackEndMediaPlayer.getDuration(); + } + + @Override + public void release() { + mBackEndMediaPlayer.release(); + } + + @Override + public void reset() { + mBackEndMediaPlayer.reset(); + } + + @Override + public void setVolume(float leftVolume, float rightVolume) { + mBackEndMediaPlayer.setVolume(leftVolume, rightVolume); + } + + @Override + public int getAudioSessionId() { + return mBackEndMediaPlayer.getAudioSessionId(); + } + + @Override + public MediaInfo getMediaInfo() { + return mBackEndMediaPlayer.getMediaInfo(); + } + + @Override + public void setLogEnabled(boolean enable) { + + } + + @Override + public boolean isPlayable() { + return false; + } + + @Override + public void setOnPreparedListener(OnPreparedListener listener) { + if (listener != null) { + final OnPreparedListener finalListener = listener; + mBackEndMediaPlayer.setOnPreparedListener(new OnPreparedListener() { + @Override + public void onPrepared(IMediaPlayer mp) { + finalListener.onPrepared(MediaPlayerProxy.this); + } + }); + } else { + mBackEndMediaPlayer.setOnPreparedListener(null); + } + } + + @Override + public void setOnCompletionListener(OnCompletionListener listener) { + if (listener != null) { + final OnCompletionListener finalListener = listener; + mBackEndMediaPlayer.setOnCompletionListener(new OnCompletionListener() { + @Override + public void onCompletion(IMediaPlayer mp) { + finalListener.onCompletion(MediaPlayerProxy.this); + } + }); + } else { + mBackEndMediaPlayer.setOnCompletionListener(null); + } + } + + @Override + public void setOnBufferingUpdateListener(OnBufferingUpdateListener listener) { + if (listener != null) { + final OnBufferingUpdateListener finalListener = listener; + mBackEndMediaPlayer.setOnBufferingUpdateListener(new OnBufferingUpdateListener() { + @Override + public void onBufferingUpdate(IMediaPlayer mp, int percent) { + finalListener.onBufferingUpdate(MediaPlayerProxy.this, percent); + } + }); + } else { + mBackEndMediaPlayer.setOnBufferingUpdateListener(null); + } + } + + @Override + public void setOnSeekCompleteListener(OnSeekCompleteListener listener) { + if (listener != null) { + final OnSeekCompleteListener finalListener = listener; + mBackEndMediaPlayer.setOnSeekCompleteListener(new OnSeekCompleteListener() { + @Override + public void onSeekComplete(IMediaPlayer mp) { + finalListener.onSeekComplete(MediaPlayerProxy.this); + } + }); + } else { + mBackEndMediaPlayer.setOnSeekCompleteListener(null); + } + } + + @Override + public void setOnVideoSizeChangedListener(OnVideoSizeChangedListener listener) { + if (listener != null) { + final OnVideoSizeChangedListener finalListener = listener; + mBackEndMediaPlayer.setOnVideoSizeChangedListener(new OnVideoSizeChangedListener() { + @Override + public void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sar_num, int sar_den) { + finalListener.onVideoSizeChanged(MediaPlayerProxy.this, width, height, sar_num, sar_den); + } + }); + } else { + mBackEndMediaPlayer.setOnVideoSizeChangedListener(null); + } + } + + @Override + public void setOnErrorListener(OnErrorListener listener) { + if (listener != null) { + final OnErrorListener finalListener = listener; + mBackEndMediaPlayer.setOnErrorListener(new OnErrorListener() { + @Override + public boolean onError(IMediaPlayer mp, int what, int extra) { + return finalListener.onError(MediaPlayerProxy.this, what, extra); + } + }); + } else { + mBackEndMediaPlayer.setOnErrorListener(null); + } + } + + @Override + public void setOnInfoListener(OnInfoListener listener) { + if (listener != null) { + final OnInfoListener finalListener = listener; + mBackEndMediaPlayer.setOnInfoListener(new OnInfoListener() { + @Override + public boolean onInfo(IMediaPlayer mp, int what, int extra) { + return finalListener.onInfo(MediaPlayerProxy.this, what, extra); + } + }); + } else { + mBackEndMediaPlayer.setOnInfoListener(null); + } + } + + @Override + public void setAudioStreamType(int streamtype) { + mBackEndMediaPlayer.setAudioStreamType(streamtype); + } + + @Override + public void setKeepInBackground(boolean keepInBackground) { + mBackEndMediaPlayer.setKeepInBackground(keepInBackground); + } + + @Override + public int getVideoSarNum() { + return mBackEndMediaPlayer.getVideoSarNum(); + } + + @Override + public int getVideoSarDen() { + return mBackEndMediaPlayer.getVideoSarDen(); + } + + @Override + public void setWakeMode(Context context, int mode) { + mBackEndMediaPlayer.setWakeMode(context, mode); + } + + @Override + public ITrackInfo[] getTrackInfo() { + return mBackEndMediaPlayer.getTrackInfo(); + } + + @Override + public void setLooping(boolean looping) { + mBackEndMediaPlayer.setLooping(looping); + } + + @Override + public boolean isLooping() { + return mBackEndMediaPlayer.isLooping(); + } +} diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/TextureMediaPlayer.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/TextureMediaPlayer.java new file mode 100644 index 0000000..22a269e --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/TextureMediaPlayer.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2015 Zhang Rui + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tv.danmaku.ijk.media.player; + +import android.annotation.TargetApi; +import android.graphics.SurfaceTexture; +import android.os.Build; +import android.view.Surface; +import android.view.SurfaceHolder; + +@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) +public class TextureMediaPlayer extends MediaPlayerProxy implements IMediaPlayer, ISurfaceTextureHolder { + private SurfaceTexture mSurfaceTexture; + private ISurfaceTextureHost mSurfaceTextureHost; + + public TextureMediaPlayer(IMediaPlayer backEndMediaPlayer) { + super(backEndMediaPlayer); + } + + public void releaseSurfaceTexture() { + if (mSurfaceTexture != null) { + if (mSurfaceTextureHost != null) { + mSurfaceTextureHost.releaseSurfaceTexture(mSurfaceTexture); + } else { + mSurfaceTexture.release(); + } + mSurfaceTexture = null; + } + } + + //-------------------- + // IMediaPlayer + //-------------------- + @Override + public void reset() { + super.reset(); + releaseSurfaceTexture(); + } + + @Override + public void release() { + super.release(); + releaseSurfaceTexture(); + } + + @Override + public void setDisplay(SurfaceHolder sh) { + if (mSurfaceTexture == null) + super.setDisplay(sh); + } + + @Override + public void setSurface(Surface surface) { + if (mSurfaceTexture == null) + super.setSurface(surface); + } + + //-------------------- + // ISurfaceTextureHolder + //-------------------- + + @Override + public void setSurfaceTexture(SurfaceTexture surfaceTexture) { + if (mSurfaceTexture == surfaceTexture) + return; + + releaseSurfaceTexture(); + mSurfaceTexture = surfaceTexture; + if (surfaceTexture == null) { + super.setSurface(null); + } else { + super.setSurface(new Surface(surfaceTexture)); + } + } + + @Override + public SurfaceTexture getSurfaceTexture() { + return mSurfaceTexture; + } + + @Override + public void setSurfaceTextureHost(ISurfaceTextureHost surfaceTextureHost) { + mSurfaceTextureHost = surfaceTextureHost; + } +} diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/annotations/AccessedByNative.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/annotations/AccessedByNative.java new file mode 100644 index 0000000..c613660 --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/annotations/AccessedByNative.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2013-2014 Zhang Rui + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tv.danmaku.ijk.media.player.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * is used by the JNI generator to create the necessary JNI + * bindings and expose this method to native code. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.CLASS) +public @interface AccessedByNative { +} \ No newline at end of file diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/annotations/CalledByNative.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/annotations/CalledByNative.java new file mode 100644 index 0000000..2a2caf3 --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/annotations/CalledByNative.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2013-2014 Zhang Rui + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tv.danmaku.ijk.media.player.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * is used by the JNI generator to create the necessary JNI + * bindings and expose this method to native code. + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.CLASS) +public @interface CalledByNative { + /* + * If present, tells which inner class the method belongs to. + */ + String value() default ""; +} \ No newline at end of file diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/exceptions/IjkMediaException.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/exceptions/IjkMediaException.java new file mode 100644 index 0000000..dbd1add --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/exceptions/IjkMediaException.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2013-2014 Zhang Rui + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tv.danmaku.ijk.media.player.exceptions; + +public class IjkMediaException extends Exception { + private static final long serialVersionUID = 7234796519009099506L; +} diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/ffmpeg/FFmpegApi.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/ffmpeg/FFmpegApi.java new file mode 100644 index 0000000..e13ba1b --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/ffmpeg/FFmpegApi.java @@ -0,0 +1,5 @@ +package tv.danmaku.ijk.media.player.ffmpeg; + +public class FFmpegApi { + public static native String av_base64_encode(byte in[]); +} diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/AndroidMediaFormat.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/AndroidMediaFormat.java new file mode 100644 index 0000000..9338a24 --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/AndroidMediaFormat.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015 Zhang Rui + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tv.danmaku.ijk.media.player.misc; + +import android.annotation.TargetApi; +import android.media.MediaFormat; +import android.os.Build; + +public class AndroidMediaFormat implements IMediaFormat { + private final MediaFormat mMediaFormat; + + public AndroidMediaFormat(MediaFormat mediaFormat) { + mMediaFormat = mediaFormat; + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + @Override + public int getInteger(String name) { + if (mMediaFormat == null) + return 0; + + return mMediaFormat.getInteger(name); + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + @Override + public String getString(String name) { + if (mMediaFormat == null) + return null; + + return mMediaFormat.getString(name); + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + @Override + public String toString() { + StringBuilder out = new StringBuilder(128); + out.append(getClass().getName()); + out.append('{'); + if (mMediaFormat != null) { + out.append(mMediaFormat.toString()); + } else { + out.append("null"); + } + out.append('}'); + return out.toString(); + } +} diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/AndroidTrackInfo.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/AndroidTrackInfo.java new file mode 100644 index 0000000..33e7556 --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/AndroidTrackInfo.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2015 Zhang Rui + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tv.danmaku.ijk.media.player.misc; + +import android.annotation.TargetApi; +import android.media.MediaFormat; +import android.media.MediaPlayer; +import android.os.Build; + +public class AndroidTrackInfo implements ITrackInfo { + private final MediaPlayer.TrackInfo mTrackInfo; + + public static AndroidTrackInfo[] fromMediaPlayer(MediaPlayer mp) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) + return fromTrackInfo(mp.getTrackInfo()); + + return null; + } + + private static AndroidTrackInfo[] fromTrackInfo(MediaPlayer.TrackInfo[] trackInfos) { + if (trackInfos == null) + return null; + + AndroidTrackInfo androidTrackInfo[] = new AndroidTrackInfo[trackInfos.length]; + for (int i = 0; i < trackInfos.length; ++i) { + androidTrackInfo[i] = new AndroidTrackInfo(trackInfos[i]); + } + + return androidTrackInfo; + } + + private AndroidTrackInfo(MediaPlayer.TrackInfo trackInfo) { + mTrackInfo = trackInfo; + } + + @TargetApi(Build.VERSION_CODES.KITKAT) + @Override + public IMediaFormat getFormat() { + if (mTrackInfo == null) + return null; + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) + return null; + + MediaFormat mediaFormat = mTrackInfo.getFormat(); + if (mediaFormat == null) + return null; + + return new AndroidMediaFormat(mediaFormat); + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + @Override + public String getLanguage() { + if (mTrackInfo == null) + return "und"; + + return mTrackInfo.getLanguage(); + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + @Override + public int getTrackType() { + if (mTrackInfo == null) + return MEDIA_TRACK_TYPE_UNKNOWN; + + return mTrackInfo.getTrackType(); + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + @Override + public String toString() { + StringBuilder out = new StringBuilder(128); + out.append(getClass().getSimpleName()); + out.append('{'); + if (mTrackInfo != null) { + out.append(mTrackInfo.toString()); + } else { + out.append("null"); + } + out.append('}'); + return out.toString(); + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + @Override + public String getInfoInline() { + if (mTrackInfo != null) { + return mTrackInfo.toString(); + } else { + return "null"; + } + } +} diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IMediaDataSource.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IMediaDataSource.java new file mode 100644 index 0000000..a298aa9 --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IMediaDataSource.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2015 Zhang Rui + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tv.danmaku.ijk.media.player.misc; + +import java.io.IOException; + +@SuppressWarnings("RedundantThrows") +public interface IMediaDataSource { + int readAt(long position, byte[] buffer, int offset, int size) throws IOException; + + long getSize() throws IOException; + + void close() throws IOException; +} diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IMediaFormat.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IMediaFormat.java new file mode 100644 index 0000000..b1cd4db --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IMediaFormat.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 Zhang Rui + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tv.danmaku.ijk.media.player.misc; + +public interface IMediaFormat { + // Common keys + String KEY_MIME = "mime"; + + // Video Keys + String KEY_WIDTH = "width"; + String KEY_HEIGHT = "height"; + + String getString(String name); + + int getInteger(String name); +} diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/ITrackInfo.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/ITrackInfo.java new file mode 100644 index 0000000..a9c5101 --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/ITrackInfo.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2015 Zhang Rui + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tv.danmaku.ijk.media.player.misc; + +public interface ITrackInfo { + int MEDIA_TRACK_TYPE_AUDIO = 2; + int MEDIA_TRACK_TYPE_METADATA = 5; + int MEDIA_TRACK_TYPE_SUBTITLE = 4; + int MEDIA_TRACK_TYPE_TIMEDTEXT = 3; + int MEDIA_TRACK_TYPE_UNKNOWN = 0; + int MEDIA_TRACK_TYPE_VIDEO = 1; + + IMediaFormat getFormat(); + + String getLanguage(); + + int getTrackType(); + + String getInfoInline(); +} diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IjkMediaFormat.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IjkMediaFormat.java new file mode 100644 index 0000000..f6ca505 --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IjkMediaFormat.java @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2015 Zhang Rui + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tv.danmaku.ijk.media.player.misc; + +import android.annotation.TargetApi; +import android.os.Build; +import android.text.TextUtils; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +import tv.danmaku.ijk.media.player.IjkMediaMeta; + +public class IjkMediaFormat implements IMediaFormat { + // Common + public static final String KEY_IJK_CODEC_LONG_NAME_UI = "ijk-codec-long-name-ui"; + public static final String KEY_IJK_BIT_RATE_UI = "ijk-bit-rate-ui"; + + // Video + public static final String KEY_IJK_CODEC_PROFILE_LEVEL_UI = "ijk-profile-level-ui"; + public static final String KEY_IJK_CODEC_PIXEL_FORMAT_UI = "ijk-pixel-format-ui"; + public static final String KEY_IJK_RESOLUTION_UI = "ijk-resolution-ui"; + public static final String KEY_IJK_FRAME_RATE_UI = "ijk-frame-rate-ui"; + + // Audio + public static final String KEY_IJK_SAMPLE_RATE_UI = "ijk-sample-rate-ui"; + public static final String KEY_IJK_CHANNEL_UI = "ijk-channel-ui"; + + // Codec + public static final String CODEC_NAME_H264 = "h264"; + + public final IjkMediaMeta.IjkStreamMeta mMediaFormat; + + public IjkMediaFormat(IjkMediaMeta.IjkStreamMeta streamMeta) { + mMediaFormat = streamMeta; + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + @Override + public int getInteger(String name) { + if (mMediaFormat == null) + return 0; + + return mMediaFormat.getInt(name); + } + + @Override + public String getString(String name) { + if (mMediaFormat == null) + return null; + + if (sFormatterMap.containsKey(name)) { + Formatter formatter = sFormatterMap.get(name); + return formatter.format(this); + } + + return mMediaFormat.getString(name); + } + + //------------------------- + // Formatter + //------------------------- + + private static abstract class Formatter { + public String format(IjkMediaFormat mediaFormat) { + String value = doFormat(mediaFormat); + if (TextUtils.isEmpty(value)) + return getDefaultString(); + return value; + } + + protected abstract String doFormat(IjkMediaFormat mediaFormat); + + @SuppressWarnings("SameReturnValue") + protected String getDefaultString() { + return "N/A"; + } + } + + private static final Map sFormatterMap = new HashMap(); + + { + sFormatterMap.put(KEY_IJK_CODEC_LONG_NAME_UI, new Formatter() { + @Override + public String doFormat(IjkMediaFormat mediaFormat) { + return mMediaFormat.getString(IjkMediaMeta.IJKM_KEY_CODEC_LONG_NAME); + } + }); + sFormatterMap.put(KEY_IJK_BIT_RATE_UI, new Formatter() { + @Override + protected String doFormat(IjkMediaFormat mediaFormat) { + int bitRate = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_BITRATE); + if (bitRate <= 0) { + return null; + } else if (bitRate < 1000) { + return String.format(Locale.US, "%d bit/s", bitRate); + } else { + return String.format(Locale.US, "%d kb/s", bitRate / 1000); + } + } + }); + sFormatterMap.put(KEY_IJK_CODEC_PROFILE_LEVEL_UI, new Formatter() { + @Override + protected String doFormat(IjkMediaFormat mediaFormat) { + String profile = mediaFormat.getString(IjkMediaMeta.IJKM_KEY_CODEC_PROFILE); + if (TextUtils.isEmpty(profile)) + return null; + + StringBuilder sb = new StringBuilder(); + sb.append(profile); + + String codecName = mediaFormat.getString(IjkMediaMeta.IJKM_KEY_CODEC_NAME); + if (!TextUtils.isEmpty(codecName) && codecName.equalsIgnoreCase(CODEC_NAME_H264)) { + int level = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_CODEC_LEVEL); + if (level < 10) + return sb.toString(); + + sb.append(" Profile Level "); + sb.append((level / 10) % 10); + if ((level % 10) != 0) { + sb.append("."); + sb.append(level % 10); + } + } + + return sb.toString(); + } + }); + sFormatterMap.put(KEY_IJK_CODEC_PIXEL_FORMAT_UI, new Formatter() { + @Override + protected String doFormat(IjkMediaFormat mediaFormat) { + return mediaFormat.getString(IjkMediaMeta.IJKM_KEY_CODEC_PIXEL_FORMAT); + } + }); + sFormatterMap.put(KEY_IJK_RESOLUTION_UI, new Formatter() { + @Override + protected String doFormat(IjkMediaFormat mediaFormat) { + int width = mediaFormat.getInteger(KEY_WIDTH); + int height = mediaFormat.getInteger(KEY_HEIGHT); + int sarNum = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_SAR_NUM); + int sarDen = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_SAR_DEN); + + if (width <= 0 || height <= 0) { + return null; + } else if (sarNum <= 0 || sarDen <= 0) { + return String.format(Locale.US, "%d x %d", width, height); + } else { + return String.format(Locale.US, "%d x %d [SAR %d:%d]", width, + height, sarNum, sarDen); + } + } + }); + sFormatterMap.put(KEY_IJK_FRAME_RATE_UI, new Formatter() { + @Override + protected String doFormat(IjkMediaFormat mediaFormat) { + int fpsNum = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_FPS_NUM); + int fpsDen = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_FPS_DEN); + if (fpsNum <= 0 || fpsDen <= 0) { + return null; + } else { + return String.valueOf(((float) (fpsNum)) / fpsDen); + } + } + }); + sFormatterMap.put(KEY_IJK_SAMPLE_RATE_UI, new Formatter() { + @Override + protected String doFormat(IjkMediaFormat mediaFormat) { + int sampleRate = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_SAMPLE_RATE); + if (sampleRate <= 0) { + return null; + } else { + return String.format(Locale.US, "%d Hz", sampleRate); + } + } + }); + sFormatterMap.put(KEY_IJK_CHANNEL_UI, new Formatter() { + @Override + protected String doFormat(IjkMediaFormat mediaFormat) { + int channelLayout = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_CHANNEL_LAYOUT); + if (channelLayout <= 0) { + return null; + } else { + if (channelLayout == IjkMediaMeta.AV_CH_LAYOUT_MONO) { + return "mono"; + } else if (channelLayout == IjkMediaMeta.AV_CH_LAYOUT_STEREO) { + return "stereo"; + } else { + return String.format(Locale.US, "%x", channelLayout); + } + } + } + }); + } +} diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IjkTrackInfo.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IjkTrackInfo.java new file mode 100644 index 0000000..f825c27 --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IjkTrackInfo.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2015 Zhang Rui + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tv.danmaku.ijk.media.player.misc; + +import android.text.TextUtils; + +import tv.danmaku.ijk.media.player.IjkMediaMeta; + +public class IjkTrackInfo implements ITrackInfo { + private int mTrackType = MEDIA_TRACK_TYPE_UNKNOWN; + private IjkMediaMeta.IjkStreamMeta mStreamMeta; + + public IjkTrackInfo(IjkMediaMeta.IjkStreamMeta streamMeta) { + mStreamMeta = streamMeta; + } + + public void setMediaMeta(IjkMediaMeta.IjkStreamMeta streamMeta) { + mStreamMeta = streamMeta; + } + + @Override + public IMediaFormat getFormat() { + return new IjkMediaFormat(mStreamMeta); + } + + @Override + public String getLanguage() { + if (mStreamMeta == null || TextUtils.isEmpty(mStreamMeta.mLanguage)) + return "und"; + + return mStreamMeta.mLanguage; + } + + @Override + public int getTrackType() { + return mTrackType; + } + + public void setTrackType(int trackType) { + mTrackType = trackType; + } + + @Override + public String toString() { + return getClass().getSimpleName() + '{' + getInfoInline() + "}"; + } + + @Override + public String getInfoInline() { + StringBuilder out = new StringBuilder(128); + switch (mTrackType) { + case MEDIA_TRACK_TYPE_VIDEO: + out.append("VIDEO"); + out.append(", "); + out.append(mStreamMeta.getCodecShortNameInline()); + out.append(", "); + out.append(mStreamMeta.getBitrateInline()); + out.append(", "); + out.append(mStreamMeta.getResolutionInline()); + break; + case MEDIA_TRACK_TYPE_AUDIO: + out.append("AUDIO"); + out.append(", "); + out.append(mStreamMeta.getCodecShortNameInline()); + out.append(", "); + out.append(mStreamMeta.getBitrateInline()); + out.append(", "); + out.append(mStreamMeta.getSampleRateInline()); + break; + case MEDIA_TRACK_TYPE_TIMEDTEXT: + out.append("TIMEDTEXT"); + break; + case MEDIA_TRACK_TYPE_SUBTITLE: + out.append("SUBTITLE"); + break; + default: + out.append("UNKNOWN"); + break; + } + return out.toString(); + } +} diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/pragma/DebugLog.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/pragma/DebugLog.java new file mode 100644 index 0000000..7ccd89d --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/pragma/DebugLog.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2013 Zhang Rui + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tv.danmaku.ijk.media.player.pragma; + +import java.util.Locale; + + +import android.util.Log; + +@SuppressWarnings({"SameParameterValue", "WeakerAccess"}) +public class DebugLog { + public static final boolean ENABLE_ERROR = Pragma.ENABLE_VERBOSE; + public static final boolean ENABLE_INFO = Pragma.ENABLE_VERBOSE; + public static final boolean ENABLE_WARN = Pragma.ENABLE_VERBOSE; + public static final boolean ENABLE_DEBUG = Pragma.ENABLE_VERBOSE; + public static final boolean ENABLE_VERBOSE = Pragma.ENABLE_VERBOSE; + + public static void e(String tag, String msg) { + if (ENABLE_ERROR) { + Log.e(tag, msg); + } + } + + public static void e(String tag, String msg, Throwable tr) { + if (ENABLE_ERROR) { + Log.e(tag, msg, tr); + } + } + + public static void efmt(String tag, String fmt, Object... args) { + if (ENABLE_ERROR) { + String msg = String.format(Locale.US, fmt, args); + Log.e(tag, msg); + } + } + + public static void i(String tag, String msg) { + if (ENABLE_INFO) { + Log.i(tag, msg); + } + } + + public static void i(String tag, String msg, Throwable tr) { + if (ENABLE_INFO) { + Log.i(tag, msg, tr); + } + } + + public static void ifmt(String tag, String fmt, Object... args) { + if (ENABLE_INFO) { + String msg = String.format(Locale.US, fmt, args); + Log.i(tag, msg); + } + } + + public static void w(String tag, String msg) { + if (ENABLE_WARN) { + Log.w(tag, msg); + } + } + + public static void w(String tag, String msg, Throwable tr) { + if (ENABLE_WARN) { + Log.w(tag, msg, tr); + } + } + + public static void wfmt(String tag, String fmt, Object... args) { + if (ENABLE_WARN) { + String msg = String.format(Locale.US, fmt, args); + Log.w(tag, msg); + } + } + + public static void d(String tag, String msg) { + if (ENABLE_DEBUG) { + Log.d(tag, msg); + } + } + + public static void d(String tag, String msg, Throwable tr) { + if (ENABLE_DEBUG) { + Log.d(tag, msg, tr); + } + } + + public static void dfmt(String tag, String fmt, Object... args) { + if (ENABLE_DEBUG) { + String msg = String.format(Locale.US, fmt, args); + Log.d(tag, msg); + } + } + + public static void v(String tag, String msg) { + if (ENABLE_VERBOSE) { + Log.v(tag, msg); + } + } + + public static void v(String tag, String msg, Throwable tr) { + if (ENABLE_VERBOSE) { + Log.v(tag, msg, tr); + } + } + + public static void vfmt(String tag, String fmt, Object... args) { + if (ENABLE_VERBOSE) { + String msg = String.format(Locale.US, fmt, args); + Log.v(tag, msg); + } + } + + public static void printStackTrace(Throwable e) { + if (ENABLE_WARN) { + e.printStackTrace(); + } + } + + public static void printCause(Throwable e) { + if (ENABLE_WARN) { + Throwable cause = e.getCause(); + if (cause != null) + e = cause; + + printStackTrace(e); + } + } +} diff --git a/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/pragma/Pragma.java b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/pragma/Pragma.java new file mode 100644 index 0000000..df26120 --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/pragma/Pragma.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2013 Zhang Rui + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package tv.danmaku.ijk.media.player.pragma; + +/*- + * configurated by app project + */ +public class Pragma { + public static final boolean ENABLE_VERBOSE = true; +} diff --git a/app/libraries/ijkplayer-java/src/main/jniLibs/arm64-v8a/libijkffmpeg.so b/app/libraries/ijkplayer-java/src/main/jniLibs/arm64-v8a/libijkffmpeg.so new file mode 100644 index 0000000..5b243fb Binary files /dev/null and b/app/libraries/ijkplayer-java/src/main/jniLibs/arm64-v8a/libijkffmpeg.so differ diff --git a/app/libraries/ijkplayer-java/src/main/jniLibs/arm64-v8a/libijkplayer.so b/app/libraries/ijkplayer-java/src/main/jniLibs/arm64-v8a/libijkplayer.so new file mode 100644 index 0000000..8f0f891 Binary files /dev/null and b/app/libraries/ijkplayer-java/src/main/jniLibs/arm64-v8a/libijkplayer.so differ diff --git a/app/libraries/ijkplayer-java/src/main/jniLibs/arm64-v8a/libijksdl.so b/app/libraries/ijkplayer-java/src/main/jniLibs/arm64-v8a/libijksdl.so new file mode 100644 index 0000000..3c8ad0d Binary files /dev/null and b/app/libraries/ijkplayer-java/src/main/jniLibs/arm64-v8a/libijksdl.so differ diff --git a/app/libraries/ijkplayer-java/src/main/jniLibs/armeabi-v7a/libijkffmpeg.so b/app/libraries/ijkplayer-java/src/main/jniLibs/armeabi-v7a/libijkffmpeg.so new file mode 100644 index 0000000..bb6271f Binary files /dev/null and b/app/libraries/ijkplayer-java/src/main/jniLibs/armeabi-v7a/libijkffmpeg.so differ diff --git a/app/libraries/ijkplayer-java/src/main/jniLibs/armeabi-v7a/libijkplayer.so b/app/libraries/ijkplayer-java/src/main/jniLibs/armeabi-v7a/libijkplayer.so new file mode 100644 index 0000000..7389549 Binary files /dev/null and b/app/libraries/ijkplayer-java/src/main/jniLibs/armeabi-v7a/libijkplayer.so differ diff --git a/app/libraries/ijkplayer-java/src/main/jniLibs/armeabi-v7a/libijksdl.so b/app/libraries/ijkplayer-java/src/main/jniLibs/armeabi-v7a/libijksdl.so new file mode 100644 index 0000000..b4786d7 Binary files /dev/null and b/app/libraries/ijkplayer-java/src/main/jniLibs/armeabi-v7a/libijksdl.so differ diff --git a/app/libraries/ijkplayer-java/src/main/jniLibs/armeabi/libijkffmpeg.so b/app/libraries/ijkplayer-java/src/main/jniLibs/armeabi/libijkffmpeg.so new file mode 100644 index 0000000..a7e85d2 Binary files /dev/null and b/app/libraries/ijkplayer-java/src/main/jniLibs/armeabi/libijkffmpeg.so differ diff --git a/app/libraries/ijkplayer-java/src/main/jniLibs/armeabi/libijkplayer.so b/app/libraries/ijkplayer-java/src/main/jniLibs/armeabi/libijkplayer.so new file mode 100644 index 0000000..0003292 Binary files /dev/null and b/app/libraries/ijkplayer-java/src/main/jniLibs/armeabi/libijkplayer.so differ diff --git a/app/libraries/ijkplayer-java/src/main/jniLibs/armeabi/libijksdl.so b/app/libraries/ijkplayer-java/src/main/jniLibs/armeabi/libijksdl.so new file mode 100644 index 0000000..3ff6335 Binary files /dev/null and b/app/libraries/ijkplayer-java/src/main/jniLibs/armeabi/libijksdl.so differ diff --git a/app/libraries/ijkplayer-java/src/main/jniLibs/x86/libijkffmpeg.so b/app/libraries/ijkplayer-java/src/main/jniLibs/x86/libijkffmpeg.so new file mode 100644 index 0000000..32cd1e5 Binary files /dev/null and b/app/libraries/ijkplayer-java/src/main/jniLibs/x86/libijkffmpeg.so differ diff --git a/app/libraries/ijkplayer-java/src/main/jniLibs/x86/libijkplayer.so b/app/libraries/ijkplayer-java/src/main/jniLibs/x86/libijkplayer.so new file mode 100644 index 0000000..79eed87 Binary files /dev/null and b/app/libraries/ijkplayer-java/src/main/jniLibs/x86/libijkplayer.so differ diff --git a/app/libraries/ijkplayer-java/src/main/jniLibs/x86/libijksdl.so b/app/libraries/ijkplayer-java/src/main/jniLibs/x86/libijksdl.so new file mode 100644 index 0000000..457c156 Binary files /dev/null and b/app/libraries/ijkplayer-java/src/main/jniLibs/x86/libijksdl.so differ diff --git a/app/libraries/ijkplayer-java/src/main/jniLibs/x86_64/libijkffmpeg.so b/app/libraries/ijkplayer-java/src/main/jniLibs/x86_64/libijkffmpeg.so new file mode 100644 index 0000000..2742d06 Binary files /dev/null and b/app/libraries/ijkplayer-java/src/main/jniLibs/x86_64/libijkffmpeg.so differ diff --git a/app/libraries/ijkplayer-java/src/main/jniLibs/x86_64/libijkplayer.so b/app/libraries/ijkplayer-java/src/main/jniLibs/x86_64/libijkplayer.so new file mode 100644 index 0000000..885c2fd Binary files /dev/null and b/app/libraries/ijkplayer-java/src/main/jniLibs/x86_64/libijkplayer.so differ diff --git a/app/libraries/ijkplayer-java/src/main/jniLibs/x86_64/libijksdl.so b/app/libraries/ijkplayer-java/src/main/jniLibs/x86_64/libijksdl.so new file mode 100644 index 0000000..080157d Binary files /dev/null and b/app/libraries/ijkplayer-java/src/main/jniLibs/x86_64/libijksdl.so differ diff --git a/app/libraries/ijkplayer-java/src/main/project.properties b/app/libraries/ijkplayer-java/src/main/project.properties new file mode 100644 index 0000000..362a0a3 --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/project.properties @@ -0,0 +1,15 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-22 +android.library=true diff --git a/app/libraries/ijkplayer-java/src/main/res/values/strings.xml b/app/libraries/ijkplayer-java/src/main/res/values/strings.xml new file mode 100644 index 0000000..7356db3 --- /dev/null +++ b/app/libraries/ijkplayer-java/src/main/res/values/strings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file