init project

This commit is contained in:
leo
2023-10-07 21:31:31 +08:00
commit 6f71dbf2d3
219 changed files with 13113 additions and 0 deletions

1
ijkplayer-java/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,27 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 26
lintOptions {
abortOnError false
}
defaultConfig {
minSdkVersion 16
targetSdkVersion 26
consumerProguardFiles 'proguard-rules.pro'
versionCode 38
versionName "1.1.17.1124"
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
buildToolsVersion '28.0.3'
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
}

31
ijkplayer-java/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,31 @@
# 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 *;
#}
-keepparameternames
-renamesourcefileattribute SourceFile
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
-keep class tv.danmaku.ijk.media.widget.media.IjkVideoView {
public protected *;
}
-keep class tv.danmaku.ijk.media.widget.media.IMediaController {
public protected *;
}
-keep class tv.danmaku.ijk.media.player.** {
*;
}

View File

@@ -0,0 +1,13 @@
package tv.danmaku.ijk.media.player;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="java"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ijkplayer-java</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@@ -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

View File

@@ -0,0 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="tv.danmaku.ijk.media.player" >
</manifest>

View File

@@ -0,0 +1,113 @@
/*
* Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
*
* 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;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import tv.danmaku.ijk.media.player.R;
public class Settings {
private Context mAppContext;
private SharedPreferences mSharedPreferences;
public static final int PV_PLAYER__Auto = 0;
public static final int PV_PLAYER__AndroidMediaPlayer = 1;
public static final int PV_PLAYER__IjkMediaPlayer = 2;
public static final int PV_PLAYER__IjkExoMediaPlayer = 3;
public Settings(Context context) {
mAppContext = context.getApplicationContext();
mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(mAppContext);
}
public boolean getEnableBackgroundPlay() {
String key = mAppContext.getString(R.string.pref_key_enable_background_play);
return mSharedPreferences.getBoolean(key, false);
}
public int getPlayer() {
String key = mAppContext.getString(R.string.pref_key_player);
String value = mSharedPreferences.getString(key, "");
try {
return Integer.valueOf(value).intValue();
} catch (NumberFormatException e) {
return 0;
}
}
public boolean getUsingMediaCodec() {
String key = mAppContext.getString(R.string.pref_key_using_media_codec);
return mSharedPreferences.getBoolean(key, true);
}
public boolean getUsingMediaCodecAutoRotate() {
String key = mAppContext.getString(R.string.pref_key_using_media_codec_auto_rotate);
return mSharedPreferences.getBoolean(key, false);
}
public boolean getMediaCodecHandleResolutionChange() {
String key = mAppContext.getString(R.string.pref_key_media_codec_handle_resolution_change);
return mSharedPreferences.getBoolean(key, false);
}
public boolean getUsingOpenSLES() {
String key = mAppContext.getString(R.string.pref_key_using_opensl_es);
return mSharedPreferences.getBoolean(key, false);
}
public String getPixelFormat() {
String key = mAppContext.getString(R.string.pref_key_pixel_format);
return mSharedPreferences.getString(key, "");
}
public boolean getEnableNoView() {
String key = mAppContext.getString(R.string.pref_key_enable_no_view);
return mSharedPreferences.getBoolean(key, false);
}
public boolean getEnableSurfaceView() {
String key = mAppContext.getString(R.string.pref_key_enable_surface_view);
return mSharedPreferences.getBoolean(key, true);
}
public boolean getEnableTextureView() {
String key = mAppContext.getString(R.string.pref_key_enable_texture_view);
return mSharedPreferences.getBoolean(key, true);
}
public boolean getEnableDetachedSurfaceTextureView() {
String key = mAppContext.getString(R.string.pref_key_enable_detached_surface_texture);
return mSharedPreferences.getBoolean(key, false);
}
public boolean getUsingMediaDataSource() {
String key = mAppContext.getString(R.string.pref_key_using_mediadatasource);
return mSharedPreferences.getBoolean(key, false);
}
public String getLastDirectory() {
String key = mAppContext.getString(R.string.pref_key_last_directory);
return mSharedPreferences.getString(key, "/");
}
public void setLastDirectory(String path) {
String key = mAppContext.getString(R.string.pref_key_last_directory);
mSharedPreferences.edit().putString(key, path).apply();
}
}

View File

@@ -0,0 +1,126 @@
/*
* Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>
*
* 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;
private OnTimedTextListener mOnTimedTextListener;
protected boolean mCompleted;
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 final void setOnTimedTextListener(OnTimedTextListener listener) {
mOnTimedTextListener = listener;
}
public void resetListeners() {
mOnPreparedListener = null;
mOnBufferingUpdateListener = null;
mOnCompletionListener = null;
mOnSeekCompleteListener = null;
mOnVideoSizeChangedListener = null;
mOnErrorListener = null;
mOnInfoListener = null;
mOnTimedTextListener = null;
}
protected final void notifyOnPrepared() {
if (mOnPreparedListener != null)
mOnPreparedListener.onPrepared(this);
}
protected final void notifyOnCompletion() {
mCompleted = true;
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);
}
protected final void notifyOnTimedText(IjkTimedText text) {
if (mOnTimedTextListener != null)
mOnTimedTextListener.onTimedText(this, text);
}
public void setDataSource(IMediaDataSource mediaDataSource) {
throw new UnsupportedOperationException();
}
public boolean isCompleted(){
return mCompleted;
}
}

View File

@@ -0,0 +1,436 @@
/*
* Copyright (C) 2006 The Android Open Source Project
* Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>
*
* 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.media.TimedText;
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<String, String> 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 record(String path, int seconds) {
}
@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);
mInternalMediaPlayer.setOnTimedTextListener(mInternalListenerAdapter);
}
private class AndroidMediaPlayerListenerHolder implements
MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener,
MediaPlayer.OnBufferingUpdateListener,
MediaPlayer.OnSeekCompleteListener,
MediaPlayer.OnVideoSizeChangedListener,
MediaPlayer.OnErrorListener, MediaPlayer.OnInfoListener,
MediaPlayer.OnTimedTextListener {
public final WeakReference<AndroidMediaPlayer> mWeakMediaPlayer;
public AndroidMediaPlayerListenerHolder(AndroidMediaPlayer mp) {
mWeakMediaPlayer = new WeakReference<AndroidMediaPlayer>(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();
}
@Override
public void onTimedText(MediaPlayer mp, TimedText text) {
AndroidMediaPlayer self = mWeakMediaPlayer.get();
if (self == null)
return;
IjkTimedText ijkText = new IjkTimedText(text.getBounds(), text.getText());
notifyOnTimedText(ijkText);
}
}
}

View File

@@ -0,0 +1,208 @@
/*
* Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>
*
* 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<String, String> 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 record(String path, int seconds);
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);
void setOnTimedTextListener(OnTimedTextListener 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);
}
interface OnTimedTextListener {
void onTimedText(IMediaPlayer mp, IjkTimedText text);
}
/*--------------------
* 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);
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
*
* 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);
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
*
* 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);
}

View File

@@ -0,0 +1,22 @@
/*
* Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>
*
* 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;
}

View File

@@ -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<String, Integer> sKnownCodecList;
private static synchronized Map<String, Integer> getKnownCodecList() {
if (sKnownCodecList != null)
return sKnownCodecList;
sKnownCodecList = new TreeMap<String, Integer>(
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_TESTED);
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 (false && 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";
}
}
}

View File

@@ -0,0 +1,401 @@
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";
public static final String IJKM_KEY_TIMEDTEXT_STREAM = "timedtext";
// 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__TIMEDTEXT = "timedtext";
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";
public static final String IJKM_KEY_CODEC_PROFILE_ID = "codec_profile_id";
// 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 static final int FF_PROFILE_H264_CONSTRAINED = (1<<9); // 8+1; constraint_set1_flag
public static final int FF_PROFILE_H264_INTRA = (1<<11); // 8+3; constraint_set3_flag
public static final int FF_PROFILE_H264_BASELINE = 66;
public static final int FF_PROFILE_H264_CONSTRAINED_BASELINE = (66|FF_PROFILE_H264_CONSTRAINED);
public static final int FF_PROFILE_H264_MAIN = 77;
public static final int FF_PROFILE_H264_EXTENDED = 88;
public static final int FF_PROFILE_H264_HIGH = 100;
public static final int FF_PROFILE_H264_HIGH_10 = 110;
public static final int FF_PROFILE_H264_HIGH_10_INTRA = (110|FF_PROFILE_H264_INTRA);
public static final int FF_PROFILE_H264_HIGH_422 = 122;
public static final int FF_PROFILE_H264_HIGH_422_INTRA = (122|FF_PROFILE_H264_INTRA);
public static final int FF_PROFILE_H264_HIGH_444 = 144;
public static final int FF_PROFILE_H264_HIGH_444_PREDICTIVE = 244;
public static final int FF_PROFILE_H264_HIGH_444_INTRA = (244|FF_PROFILE_H264_INTRA);
public static final int FF_PROFILE_H264_CAVLC_444 = 44;
public Bundle mMediaMeta;
public String mFormat;
public long mDurationUS;
public long mStartUS;
public long mBitrate;
public final ArrayList<IjkStreamMeta> mStreams = new ArrayList<IjkStreamMeta>();
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<Bundle> 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);
int subtitleStreamIndex = meta.getInt(IJKM_KEY_TIMEDTEXT_STREAM, -1);
ArrayList<Bundle> 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);
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2016 Zheng Yuan <zhengyuan10503@gmail.com>
*
* 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.Rect;
import java.lang.String;
public final class IjkTimedText {
private Rect mTextBounds = null;
private String mTextChars = null;
public IjkTimedText(Rect bounds, String text) {
mTextBounds = bounds;
mTextChars = text;
}
public Rect getBounds() {
return mTextBounds;
}
public String getText() {
return mTextChars;
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>
*
* 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;
}

View File

@@ -0,0 +1,343 @@
/*
* Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
*
* 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<String, String> 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 record(String path, int seconds) {
}
@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 setOnTimedTextListener(OnTimedTextListener listener) {
if (listener != null) {
final OnTimedTextListener finalListener = listener;
mBackEndMediaPlayer.setOnTimedTextListener(new OnTimedTextListener() {
@Override
public void onTimedText(IMediaPlayer mp, IjkTimedText text) {
finalListener.onTimedText(MediaPlayerProxy.this, text);
}
});
} else {
mBackEndMediaPlayer.setOnTimedTextListener(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();
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
*
* 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;
}
}

View File

@@ -0,0 +1,14 @@
package tv.danmaku.ijk.media.player;
import tv.danmaku.ijk.media.player.annotations.AccessedByNative;
/**
* Created by jiaozebo on 2017/2/23.
*/
public class TxtOverlayAdd {
@AccessedByNative
private long mNativeMediaPlayer;
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>
*
* 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 {
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>
*
* 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 "";
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>
*
* 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;
}

View File

@@ -0,0 +1,5 @@
package tv.danmaku.ijk.media.player.ffmpeg;
public class FFmpegApi {
public static native String av_base64_encode(byte in[]);
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
*
* 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();
}
}

View File

@@ -0,0 +1,108 @@
/*
* Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
*
* 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";
}
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2016 Raymond Zheng <raymondzheng1412@gmail.com>
*
* 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 IIjkIOHttp {
int open() throws IOException;
int read(byte[] buffer, int size) throws IOException;
long seek(long offset, int whence) throws IOException;
int close() throws IOException;
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
*
* 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;
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
*
* 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);
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
*
* 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();
}

View File

@@ -0,0 +1,258 @@
/*
* Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
*
* 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_CODEC_NAME_UI = "ijk-codec-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<String, Formatter> sFormatterMap = new HashMap<String, Formatter>();
{
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_CODEC_NAME_UI, new Formatter() {
@Override
public String doFormat(IjkMediaFormat mediaFormat) {
return mMediaFormat.getString(IjkMediaMeta.IJKM_KEY_CODEC_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) {
int profileIndex = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_CODEC_PROFILE_ID);
String profile;
switch (profileIndex) {
case IjkMediaMeta.FF_PROFILE_H264_BASELINE:
profile = "Baseline";
break;
case IjkMediaMeta.FF_PROFILE_H264_CONSTRAINED_BASELINE:
profile = "Constrained Baseline";
break;
case IjkMediaMeta.FF_PROFILE_H264_MAIN:
profile = "Main";
break;
case IjkMediaMeta.FF_PROFILE_H264_EXTENDED:
profile = "Extended";
break;
case IjkMediaMeta.FF_PROFILE_H264_HIGH:
profile = "High";
break;
case IjkMediaMeta.FF_PROFILE_H264_HIGH_10:
profile = "High 10";
break;
case IjkMediaMeta.FF_PROFILE_H264_HIGH_10_INTRA:
profile = "High 10 Intra";
break;
case IjkMediaMeta.FF_PROFILE_H264_HIGH_422:
profile = "High 4:2:2";
break;
case IjkMediaMeta.FF_PROFILE_H264_HIGH_422_INTRA:
profile = "High 4:2:2 Intra";
break;
case IjkMediaMeta.FF_PROFILE_H264_HIGH_444:
profile = "High 4:4:4";
break;
case IjkMediaMeta.FF_PROFILE_H264_HIGH_444_PREDICTIVE:
profile = "High 4:4:4 Predictive";
break;
case IjkMediaMeta.FF_PROFILE_H264_HIGH_444_INTRA:
profile = "High 4:4:4 Intra";
break;
case IjkMediaMeta.FF_PROFILE_H264_CAVLC_444:
profile = "CAVLC 4:4:4";
break;
default:
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);
}
}
}
});
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
*
* 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");
out.append(", ");
out.append(mStreamMeta.mLanguage);
break;
case MEDIA_TRACK_TYPE_SUBTITLE:
out.append("SUBTITLE");
break;
default:
out.append("UNKNOWN");
break;
}
return out.toString();
}
}

View File

@@ -0,0 +1,142 @@
/*
* Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>
*
* 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);
}
}
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>
*
* 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;
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
*
* 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.widget.media;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import tv.danmaku.ijk.media.player.misc.IMediaDataSource;
public class FileMediaDataSource implements IMediaDataSource {
private RandomAccessFile mFile;
private long mFileSize;
public FileMediaDataSource(File file) throws IOException {
mFile = new RandomAccessFile(file, "r");
mFileSize = mFile.length();
}
@Override
public int readAt(long position, byte[] buffer, int offset, int size) throws IOException {
if (mFile.getFilePointer() != position)
mFile.seek(position);
if (size == 0)
return 0;
return mFile.read(buffer, 0, size);
}
@Override
public long getSize() throws IOException {
return mFileSize;
}
@Override
public void close() throws IOException {
mFileSize = 0;
mFile.close();
mFile = null;
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
*
* 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.widget.media;
import android.view.View;
import android.widget.MediaController;
public interface IMediaController {
void hide();
boolean isShowing();
void setAnchorView(View view);
void setEnabled(boolean enabled);
void setMediaPlayer(MediaController.MediaPlayerControl player);
void show(int timeout);
void show();
//----------
// Extends
//----------
void showOnce(View view);
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
*
* 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.widget.media;
import android.graphics.SurfaceTexture;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.View;
import tv.danmaku.ijk.media.player.IMediaPlayer;
public interface IRenderView {
int AR_ASPECT_FIT_PARENT = 0; // without clip
int AR_ASPECT_FILL_PARENT = 1; // may clip
int AR_ASPECT_WRAP_CONTENT = 2;
int AR_MATCH_PARENT = 3;
int AR_16_9_FIT_PARENT = 4;
int AR_4_3_FIT_PARENT = 5;
int AR_1_1 = 6;
View getView();
boolean shouldWaitForResize();
void setVideoSize(int videoWidth, int videoHeight);
void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen);
void setVideoRotation(int degree);
void setAspectRatio(int aspectRatio);
void addRenderCallback( IRenderCallback callback);
void removeRenderCallback( IRenderCallback callback);
interface ISurfaceHolder {
void bindToMediaPlayer(IMediaPlayer mp);
IRenderView getRenderView();
SurfaceHolder getSurfaceHolder();
Surface openSurface();
SurfaceTexture getSurfaceTexture();
}
interface IRenderCallback {
/**
* @param holder
* @param width could be 0
* @param height could be 0
*/
void onSurfaceCreated(ISurfaceHolder holder, int width, int height);
/**
* @param holder
* @param format could be 0
* @param width
* @param height
*/
void onSurfaceChanged( ISurfaceHolder holder, int format, int width, int height);
void onSurfaceDestroyed( ISurfaceHolder holder);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,251 @@
/*
* Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
*
* 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.widget.media;
import android.content.Context;
import android.view.View;
import java.lang.ref.WeakReference;
import tv.danmaku.ijk.media.player.R;
public final class MeasureHelper {
private WeakReference<View> mWeakView;
private int mVideoWidth;
private int mVideoHeight;
private int mVideoSarNum;
private int mVideoSarDen;
private int mVideoRotationDegree;
private int mMeasuredWidth;
private int mMeasuredHeight;
private int mCurrentAspectRatio = IRenderView.AR_ASPECT_FIT_PARENT;
public MeasureHelper(View view) {
mWeakView = new WeakReference<View>(view);
}
public View getView() {
if (mWeakView == null)
return null;
return mWeakView.get();
}
public void setVideoSize(int videoWidth, int videoHeight) {
mVideoWidth = videoWidth;
mVideoHeight = videoHeight;
}
public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) {
mVideoSarNum = videoSarNum;
mVideoSarDen = videoSarDen;
}
public void setVideoRotation(int videoRotationDegree) {
mVideoRotationDegree = videoRotationDegree;
}
/**
* Must be called by View.onMeasure(int, int)
*
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
public void doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//Log.i("@@@@", "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", "
// + MeasureSpec.toString(heightMeasureSpec) + ")");
if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) {
int tempSpec = widthMeasureSpec;
widthMeasureSpec = heightMeasureSpec;
heightMeasureSpec = tempSpec;
}
int width = View.getDefaultSize(mVideoWidth, widthMeasureSpec);
int height = View.getDefaultSize(mVideoHeight, heightMeasureSpec);
if (mCurrentAspectRatio == IRenderView.AR_MATCH_PARENT) {
width = widthMeasureSpec;
height = heightMeasureSpec;
} else if (mVideoWidth > 0 && mVideoHeight > 0) {
int widthSpecMode = View.MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = View.MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = View.MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = View.MeasureSpec.getSize(heightMeasureSpec);
if (widthSpecMode == View.MeasureSpec.AT_MOST && heightSpecMode == View.MeasureSpec.AT_MOST) {
float specAspectRatio = (float) widthSpecSize / (float) heightSpecSize;
float displayAspectRatio;
switch (mCurrentAspectRatio) {
case IRenderView.AR_16_9_FIT_PARENT:
displayAspectRatio = 16.0f / 9.0f;
if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270)
displayAspectRatio = 1.0f / displayAspectRatio;
break;
case IRenderView.AR_4_3_FIT_PARENT:
displayAspectRatio = 4.0f / 3.0f;
if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270)
displayAspectRatio = 1.0f / displayAspectRatio;
break;
case IRenderView.AR_ASPECT_FIT_PARENT:
case IRenderView.AR_ASPECT_FILL_PARENT:
case IRenderView.AR_ASPECT_WRAP_CONTENT:
default:
displayAspectRatio = (float) mVideoWidth / (float) mVideoHeight;
if (mVideoSarNum > 0 && mVideoSarDen > 0)
displayAspectRatio = displayAspectRatio * mVideoSarNum / mVideoSarDen;
break;
}
boolean shouldBeWider = displayAspectRatio > specAspectRatio;
switch (mCurrentAspectRatio) {
case IRenderView.AR_ASPECT_FIT_PARENT:
case IRenderView.AR_16_9_FIT_PARENT:
case IRenderView.AR_4_3_FIT_PARENT:
if (shouldBeWider) {
// too wide, fix width
width = widthSpecSize;
height = (int) (width / displayAspectRatio);
} else {
// too high, fix height
height = heightSpecSize;
width = (int) (height * displayAspectRatio);
}
break;
case IRenderView.AR_ASPECT_FILL_PARENT:
if (shouldBeWider) {
// not high enough, fix height
height = heightSpecSize;
width = (int) (height * displayAspectRatio);
} else {
// not wide enough, fix width
width = widthSpecSize;
height = (int) (width / displayAspectRatio);
}
break;
case IRenderView.AR_1_1:
width = height = 1;
break;
case IRenderView.AR_ASPECT_WRAP_CONTENT:
default:
if (shouldBeWider) {
// too wide, fix width
width = Math.min(mVideoWidth, widthSpecSize);
height = (int) (width / displayAspectRatio);
} else {
// too high, fix height
height = Math.min(mVideoHeight, heightSpecSize);
width = (int) (height * displayAspectRatio);
}
break;
}
} else if (widthSpecMode == View.MeasureSpec.EXACTLY && heightSpecMode == View.MeasureSpec.EXACTLY) {
// the size is fixed
width = widthSpecSize;
height = heightSpecSize;
// for compatibility, we adjust size based on aspect ratio
if (mVideoWidth * height < width * mVideoHeight) {
//Log.i("@@@", "image too wide, correcting");
width = height * mVideoWidth / mVideoHeight;
} else if (mVideoWidth * height > width * mVideoHeight) {
//Log.i("@@@", "image too tall, correcting");
height = width * mVideoHeight / mVideoWidth;
}
} else if (widthSpecMode == View.MeasureSpec.EXACTLY) {
// only the width is fixed, adjust the height to match aspect ratio if possible
width = widthSpecSize;
height = width * mVideoHeight / mVideoWidth;
if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) {
// couldn't match aspect ratio within the constraints
height = heightSpecSize;
}
} else if (heightSpecMode == View.MeasureSpec.EXACTLY) {
// only the height is fixed, adjust the width to match aspect ratio if possible
height = heightSpecSize;
width = height * mVideoWidth / mVideoHeight;
if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) {
// couldn't match aspect ratio within the constraints
width = widthSpecSize;
}
} else {
// neither the width nor the height are fixed, try to use actual video size
width = mVideoWidth;
height = mVideoHeight;
if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) {
// too tall, decrease both width and height
height = heightSpecSize;
width = height * mVideoWidth / mVideoHeight;
}
if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) {
// too wide, decrease both width and height
width = widthSpecSize;
height = width * mVideoHeight / mVideoWidth;
}
}
} else {
// no size yet, just adopt the given spec sizes
}
mMeasuredWidth = width;
mMeasuredHeight = height;
}
public int getMeasuredWidth() {
return mMeasuredWidth;
}
public int getMeasuredHeight() {
return mMeasuredHeight;
}
public void setAspectRatio(int aspectRatio) {
mCurrentAspectRatio = aspectRatio;
}
public static String getAspectRatioText(Context context, int aspectRatio) {
String text;
switch (aspectRatio) {
case IRenderView.AR_ASPECT_FIT_PARENT:
text = context.getString(R.string.VideoView_ar_aspect_fit_parent);
break;
case IRenderView.AR_ASPECT_FILL_PARENT:
text = context.getString(R.string.VideoView_ar_aspect_fill_parent);
break;
case IRenderView.AR_ASPECT_WRAP_CONTENT:
text = context.getString(R.string.VideoView_ar_aspect_wrap_content);
break;
case IRenderView.AR_MATCH_PARENT:
text = context.getString(R.string.VideoView_ar_match_parent);
break;
case IRenderView.AR_16_9_FIT_PARENT:
text = context.getString(R.string.VideoView_ar_16_9_fit_parent);
break;
case IRenderView.AR_4_3_FIT_PARENT:
text = context.getString(R.string.VideoView_ar_4_3_fit_parent);
break;
default:
text = context.getString(R.string.N_A);
break;
}
return text;
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
*
* 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.widget.media;
import tv.danmaku.ijk.media.player.IMediaPlayer;
import tv.danmaku.ijk.media.player.IjkMediaPlayer;
import tv.danmaku.ijk.media.player.MediaPlayerProxy;
import tv.danmaku.ijk.media.player.TextureMediaPlayer;
public class MediaPlayerCompat {
public static String getName(IMediaPlayer mp) {
if (mp == null) {
return "null";
} else if (mp instanceof TextureMediaPlayer) {
StringBuilder sb = new StringBuilder("TextureMediaPlayer <");
IMediaPlayer internalMediaPlayer = ((TextureMediaPlayer) mp).getInternalMediaPlayer();
if (internalMediaPlayer == null) {
sb.append("null>");
} else {
sb.append(internalMediaPlayer.getClass().getSimpleName());
sb.append(">");
}
return sb.toString();
} else {
return mp.getClass().getSimpleName();
}
}
public static IjkMediaPlayer getIjkMediaPlayer(IMediaPlayer mp) {
IjkMediaPlayer ijkMediaPlayer = null;
if (mp == null) {
return null;
} if (mp instanceof IjkMediaPlayer) {
ijkMediaPlayer = (IjkMediaPlayer) mp;
} else if (mp instanceof MediaPlayerProxy && ((MediaPlayerProxy) mp).getInternalMediaPlayer() instanceof IjkMediaPlayer) {
ijkMediaPlayer = (IjkMediaPlayer) ((MediaPlayerProxy) mp).getInternalMediaPlayer();
}
return ijkMediaPlayer;
}
public static void selectTrack(IMediaPlayer mp, int stream) {
IjkMediaPlayer ijkMediaPlayer = getIjkMediaPlayer(mp);
if (ijkMediaPlayer == null)
return;
ijkMediaPlayer.selectTrack(stream);
}
public static void deselectTrack(IMediaPlayer mp, int stream) {
IjkMediaPlayer ijkMediaPlayer = getIjkMediaPlayer(mp);
if (ijkMediaPlayer == null)
return;
ijkMediaPlayer.deselectTrack(stream);
}
public static int getSelectedTrack(IMediaPlayer mp, int trackType) {
IjkMediaPlayer ijkMediaPlayer = getIjkMediaPlayer(mp);
if (ijkMediaPlayer == null)
return -1;
return ijkMediaPlayer.getSelectedTrack(trackType);
}
}

View File

@@ -0,0 +1,282 @@
/*
* Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
*
* 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.widget.media;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import tv.danmaku.ijk.media.player.IMediaPlayer;
import tv.danmaku.ijk.media.player.ISurfaceTextureHolder;
import tv.danmaku.ijk.media.widget.media.IRenderView;
public class SurfaceRenderView extends SurfaceView implements IRenderView {
private MeasureHelper mMeasureHelper;
public SurfaceRenderView(Context context) {
super(context);
initView(context);
}
public SurfaceRenderView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public SurfaceRenderView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public SurfaceRenderView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initView(context);
}
private void initView(Context context) {
mMeasureHelper = new MeasureHelper(this);
mSurfaceCallback = new SurfaceCallback(this);
getHolder().addCallback(mSurfaceCallback);
//noinspection deprecation
getHolder().setType(SurfaceHolder.SURFACE_TYPE_NORMAL);
}
@Override
public View getView() {
return this;
}
@Override
public boolean shouldWaitForResize() {
return true;
}
//--------------------
// Layout & Measure
//--------------------
@Override
public void setVideoSize(int videoWidth, int videoHeight) {
if (videoWidth > 0 && videoHeight > 0) {
mMeasureHelper.setVideoSize(videoWidth, videoHeight);
getHolder().setFixedSize(videoWidth, videoHeight);
requestLayout();
}
}
@Override
public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) {
if (videoSarNum > 0 && videoSarDen > 0) {
mMeasureHelper.setVideoSampleAspectRatio(videoSarNum, videoSarDen);
requestLayout();
}
}
@Override
public void setVideoRotation(int degree) {
Log.e("", "SurfaceView doesn't support rotation (" + degree + ")!\n");
}
@Override
public void setAspectRatio(int aspectRatio) {
mMeasureHelper.setAspectRatio(aspectRatio);
requestLayout();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mMeasureHelper.doMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(mMeasureHelper.getMeasuredWidth(), mMeasureHelper.getMeasuredHeight());
}
//--------------------
// SurfaceViewHolder
//--------------------
private static final class InternalSurfaceHolder implements IRenderView.ISurfaceHolder {
private SurfaceRenderView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
public InternalSurfaceHolder( SurfaceRenderView surfaceView,
SurfaceHolder surfaceHolder) {
mSurfaceView = surfaceView;
mSurfaceHolder = surfaceHolder;
}
public void bindToMediaPlayer(IMediaPlayer mp) {
if (mp != null) {
if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) &&
(mp instanceof ISurfaceTextureHolder)) {
ISurfaceTextureHolder textureHolder = (ISurfaceTextureHolder) mp;
textureHolder.setSurfaceTexture(null);
}
mp.setDisplay(mSurfaceHolder);
}
}
@Override
public IRenderView getRenderView() {
return mSurfaceView;
}
@Override
public SurfaceHolder getSurfaceHolder() {
return mSurfaceHolder;
}
@Override
public SurfaceTexture getSurfaceTexture() {
return null;
}
@Override
public Surface openSurface() {
if (mSurfaceHolder == null)
return null;
return mSurfaceHolder.getSurface();
}
}
//-------------------------
// SurfaceHolder.Callback
//-------------------------
@Override
public void addRenderCallback(IRenderCallback callback) {
mSurfaceCallback.addRenderCallback(callback);
}
@Override
public void removeRenderCallback(IRenderCallback callback) {
mSurfaceCallback.removeRenderCallback(callback);
}
private SurfaceCallback mSurfaceCallback;
private static final class SurfaceCallback implements SurfaceHolder.Callback {
private SurfaceHolder mSurfaceHolder;
private boolean mIsFormatChanged;
private int mFormat;
private int mWidth;
private int mHeight;
private WeakReference<SurfaceRenderView> mWeakSurfaceView;
private Map<IRenderCallback, Object> mRenderCallbackMap = new ConcurrentHashMap<IRenderCallback, Object>();
public SurfaceCallback(SurfaceRenderView surfaceView) {
mWeakSurfaceView = new WeakReference<SurfaceRenderView>(surfaceView);
}
public void addRenderCallback(IRenderCallback callback) {
mRenderCallbackMap.put(callback, callback);
ISurfaceHolder surfaceHolder = null;
if (mSurfaceHolder != null) {
if (surfaceHolder == null)
surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);
callback.onSurfaceCreated(surfaceHolder, mWidth, mHeight);
}
if (mIsFormatChanged) {
if (surfaceHolder == null)
surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);
callback.onSurfaceChanged(surfaceHolder, mFormat, mWidth, mHeight);
}
}
public void removeRenderCallback(IRenderCallback callback) {
mRenderCallbackMap.remove(callback);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mSurfaceHolder = holder;
mIsFormatChanged = false;
mFormat = 0;
mWidth = 0;
mHeight = 0;
ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);
for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
renderCallback.onSurfaceCreated(surfaceHolder, 0, 0);
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mSurfaceHolder = null;
mIsFormatChanged = false;
mFormat = 0;
mWidth = 0;
mHeight = 0;
ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);
for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
renderCallback.onSurfaceDestroyed(surfaceHolder);
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
mSurfaceHolder = holder;
mIsFormatChanged = true;
mFormat = format;
mWidth = width;
mHeight = height;
// mMeasureHelper.setVideoSize(width, height);
ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceHolder);
for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
renderCallback.onSurfaceChanged(surfaceHolder, format, width, height);
}
}
}
//--------------------
// Accessibility
//--------------------
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(SurfaceRenderView.class.getName());
}
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
info.setClassName(SurfaceRenderView.class.getName());
}
}
}

View File

@@ -0,0 +1,368 @@
/*
* Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
*
* 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.widget.media;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.SurfaceTexture;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.TextureView;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import tv.danmaku.ijk.media.player.IMediaPlayer;
import tv.danmaku.ijk.media.player.ISurfaceTextureHolder;
import tv.danmaku.ijk.media.player.ISurfaceTextureHost;
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public class TextureRenderView extends TextureView implements IRenderView {
private static final String TAG = "TextureRenderView";
private MeasureHelper mMeasureHelper;
public TextureRenderView(Context context) {
super(context);
initView(context);
}
public TextureRenderView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public TextureRenderView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public TextureRenderView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initView(context);
}
private void initView(Context context) {
mMeasureHelper = new MeasureHelper(this);
mSurfaceCallback = new SurfaceCallback(this);
setSurfaceTextureListener(mSurfaceCallback);
}
@Override
public View getView() {
return this;
}
@Override
public boolean shouldWaitForResize() {
return false;
}
@Override
protected void onDetachedFromWindow() {
mSurfaceCallback.willDetachFromWindow();
super.onDetachedFromWindow();
mSurfaceCallback.didDetachFromWindow();
}
//--------------------
// Layout & Measure
//--------------------
@Override
public void setVideoSize(int videoWidth, int videoHeight) {
if (videoWidth > 0 && videoHeight > 0) {
mMeasureHelper.setVideoSize(videoWidth, videoHeight);
requestLayout();
}
}
@Override
public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) {
if (videoSarNum > 0 && videoSarDen > 0) {
mMeasureHelper.setVideoSampleAspectRatio(videoSarNum, videoSarDen);
requestLayout();
}
}
@Override
public void setVideoRotation(int degree) {
mMeasureHelper.setVideoRotation(degree);
setRotation(degree);
}
@Override
public void setAspectRatio(int aspectRatio) {
mMeasureHelper.setAspectRatio(aspectRatio);
requestLayout();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mMeasureHelper.doMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(mMeasureHelper.getMeasuredWidth(), mMeasureHelper.getMeasuredHeight());
}
//--------------------
// TextureViewHolder
//--------------------
public IRenderView.ISurfaceHolder getSurfaceHolder() {
return new InternalSurfaceHolder(this, mSurfaceCallback.mSurfaceTexture, mSurfaceCallback);
}
private static final class InternalSurfaceHolder implements IRenderView.ISurfaceHolder {
private TextureRenderView mTextureView;
private SurfaceTexture mSurfaceTexture;
private ISurfaceTextureHost mSurfaceTextureHost;
public InternalSurfaceHolder( TextureRenderView textureView,
SurfaceTexture surfaceTexture,
ISurfaceTextureHost surfaceTextureHost) {
mTextureView = textureView;
mSurfaceTexture = surfaceTexture;
mSurfaceTextureHost = surfaceTextureHost;
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public void bindToMediaPlayer(IMediaPlayer mp) {
if (mp == null)
return;
if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) &&
(mp instanceof ISurfaceTextureHolder)) {
ISurfaceTextureHolder textureHolder = (ISurfaceTextureHolder) mp;
mTextureView.mSurfaceCallback.setOwnSurfaceTexture(false);
SurfaceTexture surfaceTexture = textureHolder.getSurfaceTexture();
if (surfaceTexture != null) {
mTextureView.setSurfaceTexture(surfaceTexture);
} else {
textureHolder.setSurfaceTexture(mSurfaceTexture);
textureHolder.setSurfaceTextureHost(mTextureView.mSurfaceCallback);
}
} else {
mp.setSurface(openSurface());
}
}
@Override
public IRenderView getRenderView() {
return mTextureView;
}
@Override
public SurfaceHolder getSurfaceHolder() {
return null;
}
@Override
public SurfaceTexture getSurfaceTexture() {
return mSurfaceTexture;
}
@Override
public Surface openSurface() {
if (mSurfaceTexture == null)
return null;
return new Surface(mSurfaceTexture);
}
}
//-------------------------
// SurfaceHolder.Callback
//-------------------------
@Override
public void addRenderCallback(IRenderCallback callback) {
mSurfaceCallback.addRenderCallback(callback);
}
@Override
public void removeRenderCallback(IRenderCallback callback) {
mSurfaceCallback.removeRenderCallback(callback);
}
private SurfaceCallback mSurfaceCallback;
private static final class SurfaceCallback implements SurfaceTextureListener, ISurfaceTextureHost {
private SurfaceTexture mSurfaceTexture;
private boolean mIsFormatChanged;
private int mWidth;
private int mHeight;
private boolean mOwnSurfaceTexture = true;
private boolean mWillDetachFromWindow = false;
private boolean mDidDetachFromWindow = false;
private WeakReference<TextureRenderView> mWeakRenderView;
private Map<IRenderCallback, Object> mRenderCallbackMap = new ConcurrentHashMap<IRenderCallback, Object>();
public SurfaceCallback( TextureRenderView renderView) {
mWeakRenderView = new WeakReference<TextureRenderView>(renderView);
}
public void setOwnSurfaceTexture(boolean ownSurfaceTexture) {
mOwnSurfaceTexture = ownSurfaceTexture;
}
public void addRenderCallback( IRenderCallback callback) {
mRenderCallbackMap.put(callback, callback);
ISurfaceHolder surfaceHolder = null;
if (mSurfaceTexture != null) {
if (surfaceHolder == null)
surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), mSurfaceTexture, this);
callback.onSurfaceCreated(surfaceHolder, mWidth, mHeight);
}
if (mIsFormatChanged) {
if (surfaceHolder == null)
surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), mSurfaceTexture, this);
callback.onSurfaceChanged(surfaceHolder, 0, mWidth, mHeight);
}
}
public void removeRenderCallback( IRenderCallback callback) {
mRenderCallbackMap.remove(callback);
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mSurfaceTexture = surface;
mIsFormatChanged = false;
mWidth = 0;
mHeight = 0;
ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), surface, this);
for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
renderCallback.onSurfaceCreated(surfaceHolder, 0, 0);
}
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
mSurfaceTexture = surface;
mIsFormatChanged = true;
mWidth = width;
mHeight = height;
ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), surface, this);
for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
renderCallback.onSurfaceChanged(surfaceHolder, 0, width, height);
}
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
mSurfaceTexture = surface;
mIsFormatChanged = false;
mWidth = 0;
mHeight = 0;
ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakRenderView.get(), surface, this);
for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
renderCallback.onSurfaceDestroyed(surfaceHolder);
}
Log.d(TAG, "onSurfaceTextureDestroyed: destroy: " + mOwnSurfaceTexture);
return mOwnSurfaceTexture;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
//-------------------------
// ISurfaceTextureHost
//-------------------------
@Override
public void releaseSurfaceTexture(SurfaceTexture surfaceTexture) {
if (surfaceTexture == null) {
Log.d(TAG, "releaseSurfaceTexture: null");
} else if (mDidDetachFromWindow) {
if (surfaceTexture != mSurfaceTexture) {
Log.d(TAG, "releaseSurfaceTexture: didDetachFromWindow(): release different SurfaceTexture");
surfaceTexture.release();
} else if (!mOwnSurfaceTexture) {
Log.d(TAG, "releaseSurfaceTexture: didDetachFromWindow(): release detached SurfaceTexture");
surfaceTexture.release();
} else {
Log.d(TAG, "releaseSurfaceTexture: didDetachFromWindow(): already released by TextureView");
}
} else if (mWillDetachFromWindow) {
if (surfaceTexture != mSurfaceTexture) {
Log.d(TAG, "releaseSurfaceTexture: willDetachFromWindow(): release different SurfaceTexture");
surfaceTexture.release();
} else if (!mOwnSurfaceTexture) {
Log.d(TAG, "releaseSurfaceTexture: willDetachFromWindow(): re-attach SurfaceTexture to TextureView");
setOwnSurfaceTexture(true);
} else {
Log.d(TAG, "releaseSurfaceTexture: willDetachFromWindow(): will released by TextureView");
}
} else {
if (surfaceTexture != mSurfaceTexture) {
Log.d(TAG, "releaseSurfaceTexture: alive: release different SurfaceTexture");
surfaceTexture.release();
} else if (!mOwnSurfaceTexture) {
Log.d(TAG, "releaseSurfaceTexture: alive: re-attach SurfaceTexture to TextureView");
setOwnSurfaceTexture(true);
} else {
Log.d(TAG, "releaseSurfaceTexture: alive: will released by TextureView");
}
}
}
public void willDetachFromWindow() {
Log.d(TAG, "willDetachFromWindow()");
mWillDetachFromWindow = true;
}
public void didDetachFromWindow() {
Log.d(TAG, "didDetachFromWindow()");
mDidDetachFromWindow = true;
}
}
//--------------------
// Accessibility
//--------------------
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(TextureRenderView.class.getName());
}
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(TextureRenderView.class.getName());
}
}

View File

@@ -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

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- -->
<string name="N_A">N/A</string>
<string name="TrackType_video">Video</string>
<string name="TrackType_audio">Audio</string>
<string name="TrackType_subtitle">Subtitle</string>
<string name="TrackType_timedtext">Timed text</string>
<string name="TrackType_metadata">Meta data</string>
<string name="TrackType_unknown">Unknown</string>
<string name="VideoView_ar_aspect_fit_parent">Aspect / Fit parent</string>
<string name="VideoView_ar_aspect_fill_parent">Aspect / Fill parent</string>
<string name="VideoView_ar_aspect_wrap_content">Aspect / Wrap content</string>
<string name="VideoView_ar_match_parent">Free / Fill parent</string>
<string name="VideoView_ar_16_9_fit_parent">16:9 / Fit parent</string>
<string name="VideoView_ar_4_3_fit_parent">4:3 / Fit parent</string>
<string name="VideoView_render_none">Render: None</string>
<string name="VideoView_render_surface_view">Render: SurfaceView</string>
<string name="VideoView_render_texture_view">Render: TextureView</string>
<!-- -->
<string name="pref_key_enable_background_play">pref.enable_background_play</string>
<string name="pref_key_player">pref.player</string>
<!-- -->
<string name="pref_key_using_media_codec">pref.using_media_codec</string>
<string name="pref_key_using_media_codec_auto_rotate">pref.using_media_codec_auto_rotate</string>
<string name="pref_key_media_codec_handle_resolution_change">pref.media_codec_handle_resolution_change</string>
<string name="pref_key_pixel_format">pref.pixel_format</string>
<!-- -->
<string name="pref_key_using_opensl_es">pref.using_opensl_es</string>
<!-- -->
<string name="pref_key_enable_no_view">pref.enable_no_view</string>
<string name="pref_key_enable_surface_view">pref.enable_surface_view</string>
<string name="pref_key_enable_texture_view">pref.enable_texture_view</string>
<string name="pref_key_enable_detached_surface_texture">pref.enable_detached_surface_texture</string>
<!-- -->
<string name="pref_key_using_mediadatasource">pref.using_mediadatasource</string>
<!-- -->
<string name="pref_key_last_directory"></string>
</resources>