Explorar el Código

add ijkplayer library

1145873331@qq.com %!s(int64=6) %!d(string=hace) años
padre
commit
704d721c80
Se han modificado 54 ficheros con 5865 adiciones y 48 borrados
  1. BIN
      app/libs/armeabi/libijkffmpeg.so
  2. BIN
      app/libs/armeabi/libijkplayer.so
  3. BIN
      app/libs/armeabi/libijksdl.so
  4. 70 0
      app/src/main/java/com/electric/chargingpile/view/IRenderView.java
  5. 199 0
      app/src/main/java/com/electric/chargingpile/view/MeasureHelper.java
  6. 60 0
      app/src/main/java/com/electric/chargingpile/view/MediaPlayerCompat.java
  7. 238 0
      app/src/main/java/com/electric/chargingpile/view/TextureRenderView.java
  8. 1215 0
      app/src/main/java/com/electric/chargingpile/view/UpVideoView2.java
  9. BIN
      app/src/main/res/drawable-xxhdpi/icon_at.png
  10. BIN
      app/src/main/res/drawable-xxhdpi/icon_back.png
  11. BIN
      app/src/main/res/drawable-xxhdpi/icon_close.png
  12. BIN
      app/src/main/res/drawable-xxhdpi/icon_comment.png
  13. BIN
      app/src/main/res/drawable-xxhdpi/icon_expend.png
  14. BIN
      app/src/main/res/drawable-xxhdpi/icon_forward.png
  15. BIN
      app/src/main/res/drawable-xxhdpi/icon_likeed.png
  16. BIN
      app/src/main/res/drawable-xxhdpi/icon_more.png
  17. BIN
      app/src/main/res/drawable-xxhdpi/icon_write_comment.png
  18. 5 5
      app/src/main/res/layout/activity_videodetails.xml
  19. 2 2
      app/src/main/res/layout/sv_video_publish_info.xml
  20. 32 35
      app/src/main/res/layout/view_show_bottom.xml
  21. 5 6
      app/src/main/res/layout/view_show_comment.xml
  22. 1 0
      ijkplayer-java/.gitignore
  23. 21 0
      ijkplayer-java/build.gradle
  24. 3 0
      ijkplayer-java/gradle.properties
  25. 17 0
      ijkplayer-java/proguard-rules.pro
  26. 13 0
      ijkplayer-java/src/androidTest/java/tv/danmaku/ijk/media/player/ApplicationTest.java
  27. 4 0
      ijkplayer-java/src/main/AndroidManifest.xml
  28. 109 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/AbstractMediaPlayer.java
  29. 418 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/AndroidMediaPlayer.java
  30. 200 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IMediaPlayer.java
  31. 27 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/ISurfaceTextureHolder.java
  32. 23 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/ISurfaceTextureHost.java
  33. 22 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkLibLoader.java
  34. 293 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaCodecInfo.java
  35. 380 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaMeta.java
  36. 1212 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java
  37. 29 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/MediaInfo.java
  38. 323 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/MediaPlayerProxy.java
  39. 99 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/TextureMediaPlayer.java
  40. 31 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/annotations/AccessedByNative.java
  41. 35 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/annotations/CalledByNative.java
  42. 21 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/exceptions/IjkMediaException.java
  43. 5 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/ffmpeg/FFmpegApi.java
  44. 62 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/AndroidMediaFormat.java
  45. 108 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/AndroidTrackInfo.java
  46. 28 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IMediaDataSource.java
  47. 30 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IMediaFormat.java
  48. 34 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/ITrackInfo.java
  49. 209 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IjkMediaFormat.java
  50. 96 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IjkTrackInfo.java
  51. 142 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/pragma/DebugLog.java
  52. 23 0
      ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/pragma/Pragma.java
  53. 15 0
      ijkplayer-java/src/main/project.properties
  54. 6 0
      ijkplayer-java/src/main/res/values/strings.xml

BIN
app/libs/armeabi/libijkffmpeg.so


BIN
app/libs/armeabi/libijkplayer.so


BIN
app/libs/armeabi/libijksdl.so


+ 70 - 0
app/src/main/java/com/electric/chargingpile/view/IRenderView.java

@ -0,0 +1,70 @@
1
package com.electric.chargingpile.view;
2
3
import android.graphics.SurfaceTexture;
4
import android.support.annotation.NonNull;
5
import android.support.annotation.Nullable;
6
import android.view.Surface;
7
import android.view.SurfaceHolder;
8
import android.view.View;
9
10
import tv.danmaku.ijk.media.player.IMediaPlayer;
11
12
public interface IRenderView {
13
    static final int AR_ASPECT_FIT_PARENT = 0; // without clip
14
    static final int AR_ASPECT_FILL_PARENT = 1; // may clip
15
    static final int AR_ASPECT_WRAP_CONTENT = 2;
16
    static final int AR_MATCH_PARENT = 3;
17
    static final int AR_16_9_FIT_PARENT = 4;
18
    static final int AR_4_3_FIT_PARENT = 5;
19
20
    View getView();
21
22
    boolean shouldWaitForResize();
23
24
    void setVideoSize(int videoWidth, int videoHeight);
25
26
    void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen);
27
28
    void setVideoRotation(int degree);
29
30
    void setAspectRatio(int aspectRatio);
31
32
    void addRenderCallback(@NonNull IRenderCallback callback);
33
34
    void removeRenderCallback(@NonNull IRenderCallback callback);
35
36
    interface ISurfaceHolder {
37
        void bindToMediaPlayer(IMediaPlayer mp);
38
39
        @NonNull
40
        IRenderView getRenderView();
41
42
        @Nullable
43
        SurfaceHolder getSurfaceHolder();
44
45
        @Nullable
46
        Surface openSurface();
47
48
        @Nullable
49
        SurfaceTexture getSurfaceTexture();
50
    }
51
52
    public interface IRenderCallback {
53
        /**
54
         * @param holder
55
         * @param width  could be 0
56
         * @param height could be 0
57
         */
58
        void onSurfaceCreated(@NonNull ISurfaceHolder holder, int width, int height);
59
60
        /**
61
         * @param holder
62
         * @param format could be 0
63
         * @param width
64
         * @param height
65
         */
66
        void onSurfaceChanged(@NonNull ISurfaceHolder holder, int format, int width, int height);
67
68
        void onSurfaceDestroyed(@NonNull ISurfaceHolder holder);
69
    }
70
}

+ 199 - 0
app/src/main/java/com/electric/chargingpile/view/MeasureHelper.java

@ -0,0 +1,199 @@
1
package com.electric.chargingpile.view;
2
3
4
import android.view.View;
5
6
import java.lang.ref.WeakReference;
7
8
public final class MeasureHelper {
9
    private WeakReference<View> mWeakView;
10
11
    private int mVideoWidth;
12
    private int mVideoHeight;
13
    private int mVideoSarNum;
14
    private int mVideoSarDen;
15
16
    private int mVideoRotationDegree;
17
18
    private int mMeasuredWidth;
19
    private int mMeasuredHeight;
20
21
    private int mCurrentAspectRatio = IRenderView.AR_ASPECT_FIT_PARENT;
22
23
    public MeasureHelper(View view) {
24
        mWeakView = new WeakReference<View>(view);
25
    }
26
27
    public View getView() {
28
        if (mWeakView == null)
29
            return null;
30
        return mWeakView.get();
31
    }
32
33
    public void setVideoSize(int videoWidth, int videoHeight) {
34
        mVideoWidth = videoWidth;
35
        mVideoHeight = videoHeight;
36
    }
37
38
    public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) {
39
        mVideoSarNum = videoSarNum;
40
        mVideoSarDen = videoSarDen;
41
    }
42
43
    public void setVideoRotation(int videoRotationDegree) {
44
        mVideoRotationDegree = videoRotationDegree;
45
    }
46
47
    /**
48
     * Must be called by View.onMeasure(int, int)
49
     *
50
     * @param widthMeasureSpec
51
     * @param heightMeasureSpec
52
     */
53
    public void doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
54
        //Log.i("@@@@", "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", "
55
        //        + MeasureSpec.toString(heightMeasureSpec) + ")");
56
        if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270) {
57
            int tempSpec = widthMeasureSpec;
58
            widthMeasureSpec = heightMeasureSpec;
59
            heightMeasureSpec = tempSpec;
60
        }
61
62
        int width = View.getDefaultSize(mVideoWidth, widthMeasureSpec);
63
        int height = View.getDefaultSize(mVideoHeight, heightMeasureSpec);
64
        if (mCurrentAspectRatio == IRenderView.AR_MATCH_PARENT) {
65
            width = widthMeasureSpec;
66
            height = heightMeasureSpec;
67
        } else if (mVideoWidth > 0 && mVideoHeight > 0) {
68
            int widthSpecMode = View.MeasureSpec.getMode(widthMeasureSpec);
69
            int widthSpecSize = View.MeasureSpec.getSize(widthMeasureSpec);
70
            int heightSpecMode = View.MeasureSpec.getMode(heightMeasureSpec);
71
            int heightSpecSize = View.MeasureSpec.getSize(heightMeasureSpec);
72
73
            if (widthSpecMode == View.MeasureSpec.AT_MOST && heightSpecMode == View.MeasureSpec.AT_MOST) {
74
                float specAspectRatio = (float) widthSpecSize / (float) heightSpecSize;
75
                float displayAspectRatio;
76
                switch (mCurrentAspectRatio) {
77
                    case IRenderView.AR_16_9_FIT_PARENT:
78
                        displayAspectRatio = 16.0f / 9.0f;
79
                        if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270)
80
                            displayAspectRatio = 1.0f / displayAspectRatio;
81
                        break;
82
                    case IRenderView.AR_4_3_FIT_PARENT:
83
                        displayAspectRatio = 4.0f / 3.0f;
84
                        if (mVideoRotationDegree == 90 || mVideoRotationDegree == 270)
85
                            displayAspectRatio = 1.0f / displayAspectRatio;
86
                        break;
87
                    case IRenderView.AR_ASPECT_FIT_PARENT:
88
                    case IRenderView.AR_ASPECT_FILL_PARENT:
89
                    case IRenderView.AR_ASPECT_WRAP_CONTENT:
90
                    default:
91
                        displayAspectRatio = (float) mVideoWidth / (float) mVideoHeight;
92
                        if (mVideoSarNum > 0 && mVideoSarDen > 0)
93
                            displayAspectRatio = displayAspectRatio * mVideoSarNum / mVideoSarDen;
94
                        break;
95
                }
96
                boolean shouldBeWider = displayAspectRatio > specAspectRatio;
97
98
                switch (mCurrentAspectRatio) {
99
                    case IRenderView.AR_ASPECT_FIT_PARENT:
100
                    case IRenderView.AR_16_9_FIT_PARENT:
101
                    case IRenderView.AR_4_3_FIT_PARENT:
102
                        if (shouldBeWider) {
103
                            // too wide, fix width
104
                            width = widthSpecSize;
105
                            height = (int) (width / displayAspectRatio);
106
                        } else {
107
                            // too high, fix height
108
                            height = heightSpecSize;
109
                            width = (int) (height * displayAspectRatio);
110
                        }
111
                        break;
112
                    case IRenderView.AR_ASPECT_FILL_PARENT:
113
                        if (shouldBeWider) {
114
                            // not high enough, fix height
115
                            height = heightSpecSize;
116
                            width = (int) (height * displayAspectRatio);
117
                        } else {
118
                            // not wide enough, fix width
119
                            width = widthSpecSize;
120
                            height = (int) (width / displayAspectRatio);
121
                        }
122
                        break;
123
                    case IRenderView.AR_ASPECT_WRAP_CONTENT:
124
                    default:
125
                        if (shouldBeWider) {
126
                            // too wide, fix width
127
                            width = Math.min(mVideoWidth, widthSpecSize);
128
                            height = (int) (width / displayAspectRatio);
129
                        } else {
130
                            // too high, fix height
131
                            height = Math.min(mVideoHeight, heightSpecSize);
132
                            width = (int) (height * displayAspectRatio);
133
                        }
134
                        break;
135
                }
136
            } else if (widthSpecMode == View.MeasureSpec.EXACTLY && heightSpecMode == View.MeasureSpec.EXACTLY) {
137
                // the size is fixed
138
                width = widthSpecSize;
139
                height = heightSpecSize;
140
141
                // for compatibility, we adjust size based on aspect ratio
142
                if (mVideoWidth * height < width * mVideoHeight) {
143
                    //Log.i("@@@", "image too wide, correcting");
144
                    width = height * mVideoWidth / mVideoHeight;
145
                } else if (mVideoWidth * height > width * mVideoHeight) {
146
                    //Log.i("@@@", "image too tall, correcting");
147
                    height = width * mVideoHeight / mVideoWidth;
148
                }
149
            } else if (widthSpecMode == View.MeasureSpec.EXACTLY) {
150
                // only the width is fixed, adjust the height to match aspect ratio if possible
151
                width = widthSpecSize;
152
                height = width * mVideoHeight / mVideoWidth;
153
                if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) {
154
                    // couldn't match aspect ratio within the constraints
155
                    height = heightSpecSize;
156
                }
157
            } else if (heightSpecMode == View.MeasureSpec.EXACTLY) {
158
                // only the height is fixed, adjust the width to match aspect ratio if possible
159
                height = heightSpecSize;
160
                width = height * mVideoWidth / mVideoHeight;
161
                if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) {
162
                    // couldn't match aspect ratio within the constraints
163
                    width = widthSpecSize;
164
                }
165
            } else {
166
                // neither the width nor the height are fixed, try to use actual video size
167
                width = mVideoWidth;
168
                height = mVideoHeight;
169
                if (heightSpecMode == View.MeasureSpec.AT_MOST && height > heightSpecSize) {
170
                    // too tall, decrease both width and height
171
                    height = heightSpecSize;
172
                    width = height * mVideoWidth / mVideoHeight;
173
                }
174
                if (widthSpecMode == View.MeasureSpec.AT_MOST && width > widthSpecSize) {
175
                    // too wide, decrease both width and height
176
                    width = widthSpecSize;
177
                    height = width * mVideoHeight / mVideoWidth;
178
                }
179
            }
180
        } else {
181
            // no size yet, just adopt the given spec sizes
182
        }
183
184
        mMeasuredWidth = width;
185
        mMeasuredHeight = height;
186
    }
187
188
    public int getMeasuredWidth() {
189
        return mMeasuredWidth;
190
    }
191
192
    public int getMeasuredHeight() {
193
        return mMeasuredHeight;
194
    }
195
196
    public void setAspectRatio(int aspectRatio) {
197
        mCurrentAspectRatio = aspectRatio;
198
    }
199
}

+ 60 - 0
app/src/main/java/com/electric/chargingpile/view/MediaPlayerCompat.java

@ -0,0 +1,60 @@
1
package com.electric.chargingpile.view;
2
3
4
import tv.danmaku.ijk.media.player.IMediaPlayer;
5
import tv.danmaku.ijk.media.player.IjkMediaPlayer;
6
import tv.danmaku.ijk.media.player.MediaPlayerProxy;
7
import tv.danmaku.ijk.media.player.TextureMediaPlayer;
8
9
public class MediaPlayerCompat {
10
    public static String getName(IMediaPlayer mp) {
11
        if (mp == null) {
12
            return "null";
13
        } else if (mp instanceof TextureMediaPlayer) {
14
            StringBuilder sb = new StringBuilder("TextureMediaPlayer <");
15
            IMediaPlayer internalMediaPlayer = ((TextureMediaPlayer) mp).getInternalMediaPlayer();
16
            if (internalMediaPlayer == null) {
17
                sb.append("null>");
18
            } else {
19
                sb.append(internalMediaPlayer.getClass().getSimpleName());
20
                sb.append(">");
21
            }
22
            return sb.toString();
23
        } else {
24
            return mp.getClass().getSimpleName();
25
        }
26
    }
27
28
    public static IjkMediaPlayer getIjkMediaPlayer(IMediaPlayer mp) {
29
        IjkMediaPlayer ijkMediaPlayer = null;
30
        if (mp == null) {
31
            return null;
32
        } if (mp instanceof IjkMediaPlayer) {
33
            ijkMediaPlayer = (IjkMediaPlayer) mp;
34
        } else if (mp instanceof MediaPlayerProxy && ((MediaPlayerProxy) mp).getInternalMediaPlayer() instanceof IjkMediaPlayer) {
35
            ijkMediaPlayer = (IjkMediaPlayer) ((MediaPlayerProxy) mp).getInternalMediaPlayer();
36
        }
37
        return ijkMediaPlayer;
38
    }
39
40
    public static void selectTrack(IMediaPlayer mp, int stream) {
41
        IjkMediaPlayer ijkMediaPlayer = getIjkMediaPlayer(mp);
42
        if (ijkMediaPlayer == null)
43
            return;
44
        ijkMediaPlayer.selectTrack(stream);
45
    }
46
47
    public static void deselectTrack(IMediaPlayer mp, int stream) {
48
        IjkMediaPlayer ijkMediaPlayer = getIjkMediaPlayer(mp);
49
        if (ijkMediaPlayer == null)
50
            return;
51
        ijkMediaPlayer.deselectTrack(stream);
52
    }
53
54
    public static int getSelectedTrack(IMediaPlayer mp, int trackType) {
55
        IjkMediaPlayer ijkMediaPlayer = getIjkMediaPlayer(mp);
56
        if (ijkMediaPlayer == null)
57
            return -1;
58
        return ijkMediaPlayer.getSelectedTrack(trackType);
59
    }
60
}

+ 238 - 0
app/src/main/java/com/electric/chargingpile/view/TextureRenderView.java

@ -0,0 +1,238 @@
1
package com.electric.chargingpile.view;
2
3
4
import android.content.Context;
5
import android.graphics.SurfaceTexture;
6
import android.os.Build;
7
import android.support.annotation.NonNull;
8
import android.support.annotation.Nullable;
9
import android.support.annotation.RequiresApi;
10
import android.util.AttributeSet;
11
import android.util.Log;
12
import android.view.Surface;
13
import android.view.SurfaceHolder;
14
import android.view.TextureView;
15
import android.view.View;
16
17
import java.lang.ref.WeakReference;
18
import java.util.Map;
19
import java.util.concurrent.ConcurrentHashMap;
20
21
import tv.danmaku.ijk.media.player.IMediaPlayer;
22
23
/**
24
 * Created by 27536 on 2017/9/27.
25
 */
26
27
@RequiresApi(api = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
28
public class TextureRenderView extends TextureView implements IRenderView {
29
30
    private MeasureHelper mMeasureHelper;
31
    private Listener mSurfaceTextureListener;
32
33
34
    public TextureRenderView(Context context) {
35
        super(context);
36
        initView(context);
37
    }
38
39
    public TextureRenderView(Context context, AttributeSet attrs) {
40
        super(context, attrs);
41
        initView(context);
42
    }
43
44
    public TextureRenderView(Context context, AttributeSet attrs, int defStyleAttr) {
45
        super(context, attrs, defStyleAttr);
46
        initView(context);
47
    }
48
49
    private void initView(Context context) {
50
        mSurfaceTextureListener = new Listener(this);
51
        mMeasureHelper = new MeasureHelper(this);
52
        setSurfaceTextureListener(mSurfaceTextureListener);
53
    }
54
55
    @Override
56
    public View getView() {
57
        return this;
58
    }
59
60
    @Override
61
    public boolean shouldWaitForResize() {
62
        return false;
63
    }
64
65
    @Override
66
    public void setVideoSize(int videoWidth, int videoHeight) {
67
        if (videoWidth > 0 && videoHeight > 0) {
68
            mMeasureHelper.setVideoSize(videoWidth, videoHeight);
69
            requestLayout();
70
        }
71
    }
72
73
    @Override
74
    public void setVideoSampleAspectRatio(int videoSarNum, int videoSarDen) {
75
        if (videoSarNum > 0 && videoSarDen > 0) {
76
            mMeasureHelper.setVideoSampleAspectRatio(videoSarNum, videoSarDen);
77
            requestLayout();
78
        }
79
    }
80
81
    @Override
82
    public void setVideoRotation(int degree) {
83
        if (degree != getRotation()) {
84
            Log.i("setVideoRotation", "degree:" + degree);
85
            mMeasureHelper.setVideoRotation(degree);
86
            super.setRotation(degree);
87
            requestLayout();
88
        }
89
    }
90
91
    @Override
92
    public void setAspectRatio(int aspectRatio) {
93
        mMeasureHelper.setAspectRatio(aspectRatio);
94
        requestLayout();
95
    }
96
97
    @Override
98
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
99
        mMeasureHelper.doMeasure(widthMeasureSpec, heightMeasureSpec);
100
        setMeasuredDimension(mMeasureHelper.getMeasuredWidth(), mMeasureHelper.getMeasuredHeight());
101
    }
102
103
    @Override
104
    public void addRenderCallback(@NonNull IRenderCallback callback) {
105
        mSurfaceTextureListener.addRenderCallback(callback);
106
    }
107
108
    @Override
109
    public void removeRenderCallback(@NonNull IRenderCallback callback) {
110
        mSurfaceTextureListener.removeRenderCallback(callback);
111
    }
112
113
114
    private static final class Listener implements SurfaceTextureListener {
115
        SurfaceTexture mSurfaceTexture;
116
        Surface mSurface;
117
        private int mWidth;
118
        private int mHeight;
119
120
        private Map<IRenderCallback, Object> mRenderCallbackMap = new ConcurrentHashMap<>();
121
        private WeakReference<TextureRenderView> mWeakSurfaceView;
122
123
        public Listener(@NonNull TextureRenderView view) {
124
            mWeakSurfaceView = new WeakReference<>(view);
125
        }
126
127
        @Override
128
        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
129
            mWidth = 0;
130
            mHeight = 0;
131
            mSurfaceTexture = surface;
132
            mSurface = new Surface(surface);
133
134
            ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceTexture, mSurface);
135
            for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
136
                renderCallback.onSurfaceCreated(surfaceHolder, 0, 0);
137
            }
138
        }
139
140
        @Override
141
        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
142
            mSurfaceTexture = surface;
143
            mWidth = width;
144
            mHeight = height;
145
146
            ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceTexture, mSurface);
147
            for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
148
                renderCallback.onSurfaceChanged(surfaceHolder, -1, width, height);
149
            }
150
        }
151
152
        @Override
153
        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
154
            mSurfaceTexture.release();
155
            mSurfaceTexture = null;
156
            Surface s = mSurface;
157
            mSurface = null;
158
            s.release();
159
160
            ISurfaceHolder surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceTexture, mSurface);
161
            for (IRenderCallback renderCallback : mRenderCallbackMap.keySet()) {
162
                renderCallback.onSurfaceDestroyed(surfaceHolder);
163
            }
164
            return false;
165
        }
166
167
        @Override
168
        public void onSurfaceTextureUpdated(SurfaceTexture surface) {
169
170
        }
171
172
        public void addRenderCallback(@NonNull IRenderCallback callback) {
173
            mRenderCallbackMap.put(callback, callback);
174
175
            ISurfaceHolder surfaceHolder = null;
176
            if (mSurfaceTexture != null) {
177
                surfaceHolder = new InternalSurfaceHolder(mWeakSurfaceView.get(), mSurfaceTexture, mSurface);
178
                callback.onSurfaceCreated(surfaceHolder, mWidth, mHeight);
179
            }
180
181
        }
182
183
        public void removeRenderCallback(@NonNull IRenderCallback callback) {
184
            mRenderCallbackMap.remove(callback);
185
        }
186
    }
187
188
189
    private static final class InternalSurfaceHolder implements ISurfaceHolder {
190
        private TextureRenderView mRenderView;
191
        private SurfaceTexture mSurfaceTexture;
192
        private Surface mSurface;
193
194
        public InternalSurfaceHolder(@NonNull TextureRenderView surfaceView,
195
                                     @Nullable SurfaceTexture surfaceHolder,
196
                                     @Nullable Surface surface) {
197
            mRenderView = surfaceView;
198
            mSurfaceTexture = surfaceHolder;
199
            mSurface = surface;
200
        }
201
202
        @Override
203
        public void bindToMediaPlayer(IMediaPlayer mp) {
204
            if (mp != null) {
205
                Log.i("bindToMediaPlayer", "mSurface isValid" + mSurface.isValid());
206
                mp.setSurface(mSurface);
207
            }
208
        }
209
210
        @NonNull
211
        @Override
212
        public IRenderView getRenderView() {
213
            return mRenderView;
214
        }
215
216
        @Nullable
217
        @Override
218
        public SurfaceHolder getSurfaceHolder() {
219
            return null;
220
        }
221
222
        @Nullable
223
        @Override
224
        public SurfaceTexture getSurfaceTexture() {
225
            return mSurfaceTexture;
226
        }
227
228
        @Nullable
229
        @Override
230
        public Surface openSurface() {
231
            return mSurface;
232
        }
233
    }
234
235
236
237
238
}

+ 1215 - 0
app/src/main/java/com/electric/chargingpile/view/UpVideoView2.java

@ -0,0 +1,1215 @@
1
package com.electric.chargingpile.view;
2
3
import android.annotation.TargetApi;
4
import android.app.Activity;
5
import android.app.AlertDialog;
6
import android.content.Context;
7
import android.content.DialogInterface;
8
import android.content.pm.ActivityInfo;
9
import android.graphics.drawable.Drawable;
10
import android.media.AudioManager;
11
import android.media.MediaPlayer;
12
import android.net.Uri;
13
import android.os.Build;
14
import android.os.Bundle;
15
import android.support.annotation.NonNull;
16
import android.util.AttributeSet;
17
import android.util.Log;
18
import android.view.Gravity;
19
import android.view.KeyEvent;
20
import android.view.MotionEvent;
21
import android.view.View;
22
import android.view.ViewGroup;
23
import android.view.WindowManager;
24
import android.webkit.WebSettings;
25
import android.webkit.WebView;
26
import android.widget.FrameLayout;
27
import android.widget.MediaController;
28
import android.widget.TableLayout;
29
30
import java.io.IOException;
31
import java.util.HashMap;
32
import java.util.Map;
33
34
35
import tv.danmaku.ijk.media.player.IMediaPlayer;
36
import tv.danmaku.ijk.media.player.IjkMediaPlayer;
37
import tv.danmaku.ijk.media.player.misc.ITrackInfo;
38
39
40
public class UpVideoView2 extends FrameLayout implements MediaController.MediaPlayerControl {
41
    private String TAG = "UpVideoView2";
42
    // settable by the client
43
    private Uri mUri;
44
    private Map<String, String> mHeaders;
45
46
    // all possible internal states
47
    private static final int STATE_ERROR = -1;
48
    private static final int STATE_IDLE = 0;
49
    private static final int STATE_PREPARING = 1;
50
    private static final int STATE_PREPARED = 2;
51
    private static final int STATE_PLAYING = 3;
52
    private static final int STATE_PAUSED = 4;
53
    private static final int STATE_PLAYBACK_COMPLETED = 5;
54
55
    // mCurrentState is a VideoView object's current state.
56
    // mTargetState is the state that a method caller intends to reach.
57
    // For instance, regardless the VideoView object's current state,
58
    // calling pause() intends to bring the object to a target state
59
    // of STATE_PAUSED.
60
    private int mCurrentState = STATE_IDLE;
61
    private int mTargetState = STATE_IDLE;
62
63
    // All the stuff we need for playing and showing a video
64
    private IRenderView.ISurfaceHolder mSurfaceHolder = null;
65
    private IjkMediaPlayer mMediaPlayer = null;
66
    // private int         mAudioSession;
67
    private int mVideoWidth;
68
    private int mVideoHeight;
69
    private int mSurfaceWidth;
70
    private int mSurfaceHeight;
71
    private int mVideoRotationDegree;
72
    private MediaController mMediaController;
73
    private IMediaPlayer.OnCompletionListener mOnCompletionListener;
74
    private IMediaPlayer.OnPreparedListener mOnPreparedListener;
75
    private int mCurrentBufferPercentage;
76
    private IMediaPlayer.OnErrorListener mOnErrorListener;
77
    private IMediaPlayer.OnInfoListener mOnInfoListener;
78
    private IMediaPlayer.OnVideoSizeChangedListener mOnVideoSizeChangedListener;
79
    private IjkMediaPlayer.OnNativeInvokeListener mOnNativeInvokeListener;
80
    private int mSeekWhenPrepared;  // recording the seek position while preparing
81
    private boolean mCanPause = true;
82
    private boolean mCanSeekBack = true;
83
    private boolean mCanSeekForward = true;
84
85
    private int bufferSize = -1;
86
    private boolean isAutoPlay = true;
87
88
    private static final int MSG_CACHE_DRU = 20160101;
89
90
    private static final int CACHE_WATER = 1 * 1000;
91
92
    private long mPrepareStartTime = 0;
93
    private long mPrepareEndTime = 0;
94
95
    private long mSeekStartTime = 0;
96
    private long mSeekEndTime = 0;
97
98
99
    // OnNativeInvokeListener what
100
    public static final int AVAPP_EVENT_WILL_HTTP_OPEN = 1; //AVAppHttpEvent
101
    public static final int AVAPP_EVENT_DID_HTTP_OPEN = 2; //AVAppHttpEvent
102
    public static final int AVAPP_EVENT_WILL_HTTP_SEEK = 3; //AVAppHttpEvent
103
    public static final int AVAPP_EVENT_DID_HTTP_SEEK = 4; //AVAppHttpEvent
104
105
    public static final int AVAPP_EVENT_ASYNC_STATISTIC = 0x11000; //AVAppAsyncStatistic
106
    public static final int AVAPP_EVENT_ASYNC_READ_SPEED = 0x11001; //AVAppAsyncReadSpeed
107
    public static final int AVAPP_EVENT_IO_TRAFFIC = 0x12204; //AVAppIOTraffic
108
109
    public static final int AVAPP_CTRL_WILL_TCP_OPEN = 0x20001; //AVAppTcpIOControl
110
    public static final int AVAPP_CTRL_DID_TCP_OPEN = 0x20002; //AVAppTcpIOControl
111
112
    public static final int AVAPP_CTRL_WILL_HTTP_OPEN = 0x20003; //AVAppIOControl
113
    public static final int AVAPP_CTRL_WILL_LIVE_OPEN = 0x20005; //AVAppIOControl
114
115
    public static final int AVAPP_CTRL_WILL_CONCAT_SEGMENT_OPEN = 0x20007; //AVAppIOControl
116
    // OnNativeInvokeListener bundle key
117
    public static final String AVAPP_EVENT_URL = "url";
118
    public static final String AVAPP_EVENT_ERROR = "error";
119
    public static final String AVAPP_EVENT_HTTP_CODE = "http_code";
120
121
122
//    private android.os.Handler mHandler = new android.os.Handler() {
123
//        @Override
124
//        public void handleMessage(Message msg) {
125
//            switch (msg.what) {
126
//                case MSG_CACHE_DRU:
127
//                    if (mMediaPlayer != null) {
128
//
129
//                        Log.e(TAG, "audio_cache_time:" + mMediaPlayer.getAudioCachedDuration() + "   audio_cache_size" + mMediaPlayer.getAudioCachedBytes() + "  video_cache_time:" + mMediaPlayer.getVideoCachedDuration() + "  video_cache_size:" + mMediaPlayer.getVideoDecodeFramesPerSecond());
130
//                        Log.e(TAG, "audio_cache_pac:" + mMediaPlayer.getAudioCachedPackets() + "  video_cache_pac:" + mMediaPlayer.getAudioCachedPackets());
131
//
132
//                        if (mMediaPlayer.getAudioCachedDuration() > CACHE_WATER || mMediaPlayer.getVideoCachedDuration() > CACHE_WATER)
133
//                            resume();
134
//                    }
135
//                    mHandler.removeMessages(MSG_CACHE_DRU);
136
//                    mHandler.sendEmptyMessageDelayed(MSG_CACHE_DRU, 500);
137
//            }
138
//        }
139
//    };
140
141
    /** Subtitle rendering widget overlaid on top of the video. */
142
    // private RenderingWidget mSubtitleWidget;
143
144
    /**
145
     * Listener for changes to subtitle data, used to redraw when needed.
146
     */
147
    // private RenderingWidget.OnChangedListener mSubtitlesChangedListener;
148
149
    private Context mAppContext;
150
    private IRenderView mRenderView;
151
    private int mVideoSarNum;
152
    private int mVideoSarDen;
153
154
    private boolean isFullState;
155
    private ViewGroup.LayoutParams mRawParams;
156
157
    //    private MonitorRecorder monitorRecorder;
158
    private float playSpeed = .0f;
159
160
    private long bufferTime;
161
    private long startbufferTime;
162
    private static int PURSUETIME = 10 * 1000;
163
    private boolean isAutoPursue = true;
164
165
    public boolean isAutoPursue() {
166
        return isAutoPursue;
167
    }
168
169
    public void setAutoPursue(boolean autoPursue) {
170
        isAutoPursue = autoPursue;
171
    }
172
173
    private String ua = null;// user agent
174
175
    public boolean isFullState() {
176
        return isFullState;
177
    }
178
179
    public UpVideoView2(Context context) {
180
        super(context);
181
        initVideoView(context);
182
    }
183
184
    public UpVideoView2(Context context, AttributeSet attrs) {
185
        super(context, attrs);
186
        initVideoView(context);
187
    }
188
189
    public UpVideoView2(Context context, AttributeSet attrs, int defStyleAttr) {
190
        super(context, attrs, defStyleAttr);
191
        initVideoView(context);
192
    }
193
194
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
195
    public UpVideoView2(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
196
        super(context, attrs, defStyleAttr, defStyleRes);
197
        initVideoView(context);
198
    }
199
200
    // REMOVED: onMeasure
201
    // REMOVED: onInitializeAccessibilityEvent
202
    // REMOVED: onInitializeAccessibilityNodeInfo
203
    // REMOVED: resolveAdjustedSize
204
205
    private void initVideoView(Context context) {
206
        mAppContext = context.getApplicationContext();
207
        TextureRenderView renderView = new TextureRenderView(getContext());
208
        setRenderView(renderView);
209
210
        mVideoWidth = 0;
211
        mVideoHeight = 0;
212
        // REMOVED: getHolder().addCallback(mSHCallback);
213
        // REMOVED: getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
214
        setFocusable(true);
215
        setFocusableInTouchMode(true);
216
        requestFocus();
217
        // REMOVED: mPendingSubtitleTracks = new Vector<Pair<InputStream, MediaFormat>>();
218
        mCurrentState = STATE_IDLE;
219
        mTargetState = STATE_IDLE;
220
221
//        monitorRecorder = new MonitorRecorder(mAppContext);
222
223
        // user agent
224
        WebView webview;
225
        webview = new WebView(context);
226
        webview.layout(0, 0, 0, 0);
227
        WebSettings settings = webview.getSettings();
228
        this.ua = settings.getUserAgentString();
229
    }
230
231
    public void setRenderView(IRenderView renderView) {
232
        if (mRenderView != null) {
233
            if (mMediaPlayer != null)
234
                mMediaPlayer.setSurface(null);
235
236
            View renderUIView = mRenderView.getView();
237
            mRenderView.removeRenderCallback(mSHCallback);
238
            mRenderView = null;
239
            removeView(renderUIView);
240
        }
241
242
        if (renderView == null)
243
            return;
244
245
        mRenderView = renderView;
246
        renderView.setAspectRatio(mCurrentAspectRatio);
247
        if (mVideoWidth > 0 && mVideoHeight > 0)
248
            renderView.setVideoSize(mVideoWidth, mVideoHeight);
249
        if (mVideoSarNum > 0 && mVideoSarDen > 0)
250
            renderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
251
252
        View renderUIView = mRenderView.getView();
253
        LayoutParams lp = new LayoutParams(
254
                LayoutParams.WRAP_CONTENT,
255
                LayoutParams.WRAP_CONTENT,
256
                Gravity.CENTER);
257
        renderUIView.setLayoutParams(lp);
258
        addView(renderUIView);
259
260
        mRenderView.addRenderCallback(mSHCallback);
261
        mRenderView.setVideoRotation(mVideoRotationDegree);
262
    }
263
264
    /**
265
     * Sets video path.
266
     *
267
     * @param path the path of the video.
268
     */
269
    public void setVideoPath(String path) {
270
        setVideoURI(Uri.parse(path));
271
    }
272
273
    /**
274
     * Sets video URI.
275
     *
276
     * @param uri the URI of the video.
277
     */
278
    public void setVideoURI(Uri uri) {
279
        setVideoURI(uri, null);
280
    }
281
282
    /**
283
     * Sets video URI using specific headers.
284
     *
285
     * @param uri     the URI of the video.
286
     * @param headers the headers for the URI request.
287
     *                Note that the cross domain redirection is allowed by default, but that can be
288
     *                changed with key/value pairs through the headers parameter with
289
     *                "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value
290
     *                to disallow or allow cross domain redirection.
291
     */
292
    private void setVideoURI(Uri uri, Map<String, String> headers) {
293
        mUri = uri;
294
295
        if (uri.toString().startsWith("http")) {
296
            if (headers == null) {
297
                headers = new HashMap<>();
298
            }
299
            headers.put("X-Accept-Video-Encoding", "h265");
300
        }
301
302
        mHeaders = headers;
303
        mSeekWhenPrepared = 0;
304
        openVideo();
305
        requestLayout();
306
        invalidate();
307
    }
308
309
    // REMOVED: addSubtitleSource
310
    // REMOVED: mPendingSubtitleTracks
311
312
    public void stopPlayback() {
313
        if (mMediaPlayer != null) {
314
            mMediaPlayer.stop();
315
            mMediaPlayer.release();
316
317
            mMediaPlayer = null;
318
            mCurrentState = STATE_IDLE;
319
            mTargetState = STATE_IDLE;
320
            AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);
321
            am.abandonAudioFocus(null);
322
        }
323
    }
324
325
    @TargetApi(Build.VERSION_CODES.M)
326
    private void openVideo() {
327
        Log.i(TAG, "openVideo");
328
        if (mUri == null || mSurfaceHolder == null) {
329
            Log.i(TAG, "openVideo return mSurfaceHolder == null:" + (mSurfaceHolder == null));
330
            // not ready for playback just yet, will try again later
331
            return;
332
        }
333
        Log.i(TAG, "openVideo start");
334
        // we shouldn't clear the target state, because somebody might have
335
        // called start() previously
336
        release(false);
337
338
        //开始播放时间
339
//        monitorRecorder.start();
340
//        monitorRecorder.setPlayUrl(mUri.toString());
341
342
//        mHandler.removeMessages(MSG_CACHE_DRU);
343
//        mHandler.sendEmptyMessageDelayed(MSG_CACHE_DRU, 500);
344
345
        AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);
346
        am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
347
348
        try {
349
            mMediaPlayer = new IjkMediaPlayer();
350
            mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 0);
351
            mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 0);
352
            mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", IjkMediaPlayer.SDL_FCC_RV32);
353
            mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 1);
354
            mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", isAutoPlay ? 1 : 0);
355
            mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-buffer-size", 1024 * 400);
356
            mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "http-detect-range-support", 0);
357
            mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 0);
358
            mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "probesize", "64000");
359
            mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec_mpeg4", 1);
360
            mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "enable-accurate-seek", 1);
361
362
//            mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1);
363
//            mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 1);
364
365
//            mMediaPlayer.setLooping(true);
366
//            mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "sync", "ext");
367
//            mMediaPlayer.setSpeed(1.03f);
368
369
            if (bufferSize != -1) {
370
                mMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-buffer-size", bufferSize);
371
            }
372
373
            // TODO: create SubtitleController in MediaPlayer, but we need
374
            // a context for the subtitle renderers
375
            final Context context = getContext();
376
            // REMOVED: SubtitleController
377
378
            // REMOVED: mAudioSession
379
            mMediaPlayer.setOnPreparedListener(mPreparedListener);
380
            mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
381
            mMediaPlayer.setOnCompletionListener(mCompletionListener);
382
            mMediaPlayer.setOnErrorListener(mErrorListener);
383
            mMediaPlayer.setOnNativeInvokeListener(mNativeInvokeListener);
384
            mMediaPlayer.setOnInfoListener(mInfoListener);
385
            mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
386
            mCurrentBufferPercentage = 0;
387
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
388
                mMediaPlayer.setDataSource(mAppContext, mUri, mHeaders);
389
            } else {
390
                mMediaPlayer.setDataSource(mUri.toString());
391
            }
392
            bindSurfaceHolder(mMediaPlayer, mSurfaceHolder);
393
            mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
394
            mMediaPlayer.setScreenOnWhilePlaying(true);
395
            mPrepareStartTime = System.currentTimeMillis();
396
            mMediaPlayer.prepareAsync();
397
398
            if (playSpeed != .0f) {
399
                mMediaPlayer.setSpeed(playSpeed);
400
            }
401
402
            // REMOVED: mPendingSubtitleTracks
403
404
            // we don't set the target state here either, but preserve the
405
            // target state that was there before.
406
            mCurrentState = STATE_PREPARING;
407
            attachMediaController();
408
        } catch (IOException ex) {
409
            Log.w(TAG, "Unable to open content: " + mUri, ex);
410
            mCurrentState = STATE_ERROR;
411
            mTargetState = STATE_ERROR;
412
            mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
413
            return;
414
        } catch (IllegalArgumentException ex) {
415
            Log.w(TAG, "Unable to open content: " + mUri, ex);
416
            mCurrentState = STATE_ERROR;
417
            mTargetState = STATE_ERROR;
418
            mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
419
            return;
420
        } finally {
421
            // REMOVED: mPendingSubtitleTracks.clear();
422
        }
423
    }
424
425
    public void setMediaController(MediaController controller) {
426
        if (mMediaController != null) {
427
            mMediaController.hide();
428
        }
429
        mMediaController = controller;
430
        attachMediaController();
431
    }
432
433
    private void attachMediaController() {
434
        if (mMediaPlayer != null && mMediaController != null) {
435
            mMediaController.setMediaPlayer(this);
436
            View anchorView = this.getParent() instanceof View ?
437
                    (View) this.getParent() : this;
438
            mMediaController.setAnchorView(anchorView);
439
            mMediaController.setEnabled(isInPlaybackState());
440
        }
441
    }
442
443
    IMediaPlayer.OnVideoSizeChangedListener mSizeChangedListener =
444
            new IMediaPlayer.OnVideoSizeChangedListener() {
445
                public void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sarNum, int sarDen) {
446
                    if (mOnVideoSizeChangedListener != null) {
447
                        mOnVideoSizeChangedListener.onVideoSizeChanged(mp, width, height, sarNum, sarDen);
448
                    }
449
                    mVideoWidth = mp.getVideoWidth();
450
                    mVideoHeight = mp.getVideoHeight();
451
                    mVideoSarNum = mp.getVideoSarNum();
452
                    mVideoSarDen = mp.getVideoSarDen();
453
                    if (mVideoWidth != 0 && mVideoHeight != 0) {
454
                        if (mRenderView != null) {
455
                            mRenderView.setVideoSize(mVideoWidth, mVideoHeight);
456
                            mRenderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
457
                        }
458
                        // REMOVED: getHolder().setFixedSize(mVideoWidth, mVideoHeight);
459
                        requestLayout();
460
                    }
461
                }
462
            };
463
464
    IMediaPlayer.OnPreparedListener mPreparedListener = new IMediaPlayer.OnPreparedListener() {
465
        public void onPrepared(IMediaPlayer mp) {
466
            mPrepareEndTime = System.currentTimeMillis();
467
468
//            monitorRecorder.firstPacket();
469
            mCurrentState = STATE_PREPARED;
470
            mMediaPlayer.pause();
471
472
            // Get the capabilities of the player for this stream
473
            // REMOVED: Metadata
474
475
            if (mOnPreparedListener != null) {
476
                mOnPreparedListener.onPrepared(mMediaPlayer);
477
            }
478
            if (mMediaController != null) {
479
                mMediaController.setEnabled(true);
480
            }
481
            mVideoWidth = mp.getVideoWidth();
482
            mVideoHeight = mp.getVideoHeight();
483
484
//            monitorRecorder.setVideoSize(mVideoHeight, mVideoWidth);
485
//            monitorRecorder.setFirstPlayState(0);
486
//            monitorRecorder.getMetaData(mMediaPlayer._getMetaData());
487
488
            int seekToPosition = mSeekWhenPrepared;  // mSeekWhenPrepared may be changed after seekTo() call
489
            if (seekToPosition != 0) {
490
                seekTo(seekToPosition);
491
            }
492
            if (mVideoWidth != 0 && mVideoHeight != 0) {
493
                Log.i(TAG, "onPrepared mVideoWidth != 0 && mVideoHeight != 0");
494
                //Log.i("@@@@", "video size: " + mVideoWidth +"/"+ mVideoHeight);
495
                // REMOVED: getHolder().setFixedSize(mVideoWidth, mVideoHeight);
496
                if (mRenderView != null) {
497
                    Log.i(TAG, "onPrepared mRenderView != null");
498
                    mRenderView.setVideoSize(mVideoWidth, mVideoHeight);
499
                    mRenderView.setVideoSampleAspectRatio(mVideoSarNum, mVideoSarDen);
500
                    if (!mRenderView.shouldWaitForResize() || mSurfaceWidth == mVideoWidth && mSurfaceHeight == mVideoHeight) {
501
                        Log.i(TAG, "onPrepared 1");
502
                        // We didn't actually change the size (it was already at the size
503
                        // we need), so we won't get a "surface changed" callback, so
504
                        // start the video here instead of in the callback.
505
                        if (mTargetState == STATE_PLAYING) {
506
                            Log.i(TAG, "onPrepared 2");
507
                            start();
508
                            if (mMediaController != null) {
509
                                mMediaController.show();
510
                            }
511
                        } else if (!isPlaying() &&
512
                                (seekToPosition != 0 || getCurrentPosition() > 0)) {
513
                            Log.i(TAG, "onPrepared 3");
514
                            if (mMediaController != null) {
515
                                // Show the media controls when we're paused into a video and make 'em stick.
516
                                mMediaController.show(0);
517
                            }
518
                        }
519
                    }
520
                }
521
            } else {
522
                // We don't know the video size yet, but should start anyway.
523
                // The video size might be reported to us later.
524
                if (mTargetState == STATE_PLAYING) {
525
                    Log.i(TAG, "onPrepared start");
526
                    start();
527
                }
528
            }
529
        }
530
    };
531
532
    private IMediaPlayer.OnCompletionListener mCompletionListener =
533
            new IMediaPlayer.OnCompletionListener() {
534
                public void onCompletion(IMediaPlayer mp) {
535
                    mCurrentState = STATE_PLAYBACK_COMPLETED;
536
                    mTargetState = STATE_PLAYBACK_COMPLETED;
537
                    if (mMediaController != null) {
538
                        mMediaController.hide();
539
                    }
540
                    if (mOnCompletionListener != null) {
541
                        mOnCompletionListener.onCompletion(mMediaPlayer);
542
                    }
543
                }
544
            };
545
546
    private IjkMediaPlayer.OnNativeInvokeListener mNativeInvokeListener = new IjkMediaPlayer.OnNativeInvokeListener() {
547
        @Override
548
        public boolean onNativeInvoke(int what, Bundle args) {
549
            Log.i(TAG, "onNativeInvoke:" + what);
550
            if (mOnNativeInvokeListener != null) {
551
                mOnNativeInvokeListener.onNativeInvoke(what, args);
552
            }
553
            return false;
554
        }
555
    };
556
557
    private IMediaPlayer.OnInfoListener mInfoListener =
558
            new IMediaPlayer.OnInfoListener() {
559
                public boolean onInfo(IMediaPlayer mp, int arg1, int arg2) {
560
                    if (mOnInfoListener != null) {
561
                        mOnInfoListener.onInfo(mp, arg1, arg2);
562
                    }
563
                    switch (arg1) {
564
                        case IMediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING:
565
                            Log.d(TAG, "MEDIA_INFO_VIDEO_TRACK_LAGGING:");
566
                            break;
567
                        case IMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START:
568
                            Log.d(TAG, "MEDIA_INFO_VIDEO_RENDERING_START:");
569
                            break;
570
                        case IMediaPlayer.MEDIA_INFO_BUFFERING_START:
571
                            Log.e(TAG, "卡顿时间:" + bufferTime);
572
                            startbufferTime = System.currentTimeMillis();
573
                            if (bufferTime > PURSUETIME && isAutoPursue) {
574
                                bufferTime = 0;
575
                                resume();
576
                                Log.e(TAG, "卡顿重连追帧");
577
                                break;
578
                            }
579
                            if (isAutoPursue) {
580
                                reportError();
581
                            }
582
583
                            Log.d(TAG, "MEDIA_INFO_BUFFERING_START:");
584
                            break;
585
                        case IMediaPlayer.MEDIA_INFO_BUFFERING_END:
586
                            Log.e(TAG, "结束缓冲:" + bufferTime);
587
                            if (startbufferTime != 0 && isAutoPursue) {
588
                                bufferTime = System.currentTimeMillis() - startbufferTime;
589
                                if (bufferTime > 2000) {
590
                                    bufferTime = 0;
591
                                    resume();
592
                                }
593
                            }
594
                            cancelReport();
595
//                            monitorRecorder.BufferEnd();
596
                            Log.d(TAG, "MEDIA_INFO_BUFFERING_END:");
597
                            break;
598
                        case IMediaPlayer.MEDIA_INFO_NETWORK_BANDWIDTH:
599
//                            recorder.setBandwidth(arg2);
600
                            Log.d(TAG, "MEDIA_INFO_NETWORK_BANDWIDTH: " + arg2);
601
                            break;
602
                        case IMediaPlayer.MEDIA_INFO_BAD_INTERLEAVING:
603
                            Log.d(TAG, "MEDIA_INFO_BAD_INTERLEAVING:");
604
                            break;
605
                        case IMediaPlayer.MEDIA_INFO_NOT_SEEKABLE:
606
                            Log.d(TAG, "MEDIA_INFO_NOT_SEEKABLE:");
607
                            break;
608
                        case IMediaPlayer.MEDIA_INFO_METADATA_UPDATE:
609
                            Log.d(TAG, "MEDIA_INFO_METADATA_UPDATE:");
610
                            break;
611
                        case IMediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE:
612
                            Log.d(TAG, "MEDIA_INFO_UNSUPPORTED_SUBTITLE:");
613
                            break;
614
                        case IMediaPlayer.MEDIA_INFO_SUBTITLE_TIMED_OUT:
615
                            Log.d(TAG, "MEDIA_INFO_SUBTITLE_TIMED_OUT:");
616
                            break;
617
                        case IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED:
618
                            mVideoRotationDegree = arg2;
619
                            Log.d(TAG, "MEDIA_INFO_VIDEO_ROTATION_CHANGED: " + arg2);
620
                            if (mRenderView != null)
621
                                mRenderView.setVideoRotation(arg2);
622
                            break;
623
                        case IMediaPlayer.MEDIA_INFO_AUDIO_RENDERING_START:
624
                            Log.d(TAG, "MEDIA_INFO_AUDIO_RENDERING_START:");
625
                            break;
626
                    }
627
                    return true;
628
                }
629
            };
630
631
    private IMediaPlayer.OnErrorListener mErrorListener =
632
            new IMediaPlayer.OnErrorListener() {
633
                public boolean onError(IMediaPlayer mp, int framework_err, int impl_err) {
634
                    Log.e(TAG, "Error: " + framework_err + "," + impl_err);
635
636
//                    monitorRecorder.errorDate("Error: " + framework_err + "," + impl_err);
637
638
                    mCurrentState = STATE_ERROR;
639
                    mTargetState = STATE_ERROR;
640
                    if (mMediaController != null) {
641
                        mMediaController.hide();
642
                    }
643
644
                    /* If an error handler has been supplied, use it and finish. */
645
                    if (mOnErrorListener != null) {
646
                        if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) {
647
                            return true;
648
                        }
649
                    }
650
651
                    /* Otherwise, pop up an error dialog so the user knows that
652
                     * something bad has happened. Only try and pop up the dialog
653
                     * if we're attached to a window. When we're going away and no
654
                     * longer have a window, don't bother showing the user an error.
655
                     */
656
                    if (getWindowToken() != null) {
657
                        String messageId;
658
659
                        if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
660
                            messageId = "Invalid progressive playback";
661
                        } else {
662
                            messageId = "Unknown";
663
                        }
664
665
                        new AlertDialog.Builder(getContext())
666
                                .setMessage(messageId)
667
                                .setPositiveButton("OK",
668
                                        new DialogInterface.OnClickListener() {
669
                                            public void onClick(DialogInterface dialog, int whichButton) {
670
                                                /* If we get here, there is no onError listener, so
671
                                                 * at least inform them that the video is over.
672
                                                 */
673
                                                if (mOnCompletionListener != null) {
674
                                                    mOnCompletionListener.onCompletion(mMediaPlayer);
675
                                                }
676
                                            }
677
                                        })
678
                                .setCancelable(false)
679
                                .show();
680
                    }
681
                    return true;
682
                }
683
            };
684
685
    private IMediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener =
686
            new IMediaPlayer.OnBufferingUpdateListener() {
687
                public void onBufferingUpdate(IMediaPlayer mp, int percent) {
688
                    mCurrentBufferPercentage = percent;
689
                }
690
            };
691
692
    private IMediaPlayer.OnSeekCompleteListener mSeekCompleteListener = new IMediaPlayer.OnSeekCompleteListener() {
693
694
        @Override
695
        public void onSeekComplete(IMediaPlayer mp) {
696
            mSeekEndTime = System.currentTimeMillis();
697
        }
698
    };
699
700
    /**
701
     * Register a callback to be invoked when the media file
702
     * is loaded and ready to go.
703
     *
704
     * @param l The callback that will be run
705
     */
706
    public void setOnPreparedListener(IMediaPlayer.OnPreparedListener l) {
707
        mOnPreparedListener = l;
708
    }
709
710
    /**
711
     * Register a callback to be invoked when the end of a media file
712
     * has been reached during playback.
713
     *
714
     * @param l The callback that will be run
715
     */
716
    public void setOnCompletionListener(IMediaPlayer.OnCompletionListener l) {
717
        mOnCompletionListener = l;
718
    }
719
720
    /**
721
     * Register a callback to be invoked when an error occurs
722
     * during playback or setup.  If no listener is specified,
723
     * or if the listener returned false, VideoView will inform
724
     * the user of any errors.
725
     *
726
     * @param l The callback that will be run
727
     */
728
    public void setOnErrorListener(IMediaPlayer.OnErrorListener l) {
729
        mOnErrorListener = l;
730
    }
731
732
    /**
733
     * Register a callback to be invoked when an informational event
734
     * occurs during playback or setup.
735
     *
736
     * @param l The callback that will be run
737
     */
738
    public void setOnInfoListener(IMediaPlayer.OnInfoListener l) {
739
        mOnInfoListener = l;
740
    }
741
742
743
    public void setOnVideoSizeListener(IMediaPlayer.OnVideoSizeChangedListener l) {
744
        mOnVideoSizeChangedListener = l;
745
    }
746
747
    /**
748
     * @see AVAPP_EVENT_WILL_HTTP_OPEN
749
     * @see AVAPP_EVENT_HTTP_CODE
750
     * @param l
751
     */
752
    public void setOnNativeInvokeListener(IjkMediaPlayer.OnNativeInvokeListener l) {
753
        mOnNativeInvokeListener = l;
754
    }
755
756
    // REMOVED: mSHCallback
757
    private void bindSurfaceHolder(IMediaPlayer mp, IRenderView.ISurfaceHolder holder) {
758
        if (mp == null)
759
            return;
760
761
        if (holder == null) {
762
            mp.setSurface(null);
763
            return;
764
        }
765
766
        holder.bindToMediaPlayer(mp);
767
    }
768
769
    IRenderView.IRenderCallback mSHCallback = new IRenderView.IRenderCallback() {
770
        @Override
771
        public void onSurfaceChanged(@NonNull IRenderView.ISurfaceHolder holder, int format, int w, int h) {
772
            if (holder.getRenderView() != mRenderView) {
773
                Log.e(TAG, "onSurfaceChanged: unmatched render callback\n");
774
                return;
775
            }
776
            Log.i(TAG, "onSurfaceChanged");
777
            mSurfaceWidth = w;
778
            mSurfaceHeight = h;
779
            boolean isValidState = (mTargetState == STATE_PLAYING);
780
            boolean hasValidSize = !mRenderView.shouldWaitForResize() || (mVideoWidth == w && mVideoHeight == h);
781
            if (mMediaPlayer != null && isValidState && hasValidSize) {
782
                if (mSeekWhenPrepared != 0) {
783
                    seekTo(mSeekWhenPrepared);
784
                }
785
                start();
786
            }
787
        }
788
789
        @Override
790
        public void onSurfaceCreated(@NonNull IRenderView.ISurfaceHolder holder, int width, int height) {
791
            if (holder.getRenderView() != mRenderView) {
792
                Log.e(TAG, "onSurfaceCreated: unmatched render callback\n");
793
                return;
794
            }
795
            Log.i(TAG, "onSurfaceCreated");
796
            mSurfaceHolder = holder;
797
            if (mMediaPlayer != null) {
798
                Log.i(TAG, "onSurfaceCreated bindSurfaceHolder");
799
                bindSurfaceHolder(mMediaPlayer, holder);
800
            } else {
801
                Log.i(TAG, "onSurfaceCreated openVideo");
802
                // onSurfaceCreated在调用过start之后触发
803
                if (mTargetState == STATE_PLAYING) {
804
                    openVideo();
805
                    if (mMediaPlayer != null) {
806
                        Log.i(TAG, "onSurfaceCreated bindSurfaceHolder");
807
                        bindSurfaceHolder(mMediaPlayer, holder);
808
                        mCurrentState = STATE_PLAYING;
809
                        start();
810
                    }
811
                }
812
            }
813
        }
814
815
        @Override
816
        public void onSurfaceDestroyed(@NonNull IRenderView.ISurfaceHolder holder) {
817
            Log.i(TAG, "onSurfaceDestroyed1");
818
            if (holder.getRenderView() != mRenderView) {
819
                Log.e(TAG, "onSurfaceDestroyed: unmatched render callback\n");
820
                return;
821
            }
822
            Log.i(TAG, "onSurfaceDestroyed2");
823
            // after we return from this we can't use the surface any more
824
            mSurfaceHolder = null;
825
            // REMOVED: if (mMediaController != null) mMediaController.hide();
826
            // REMOVED: release(true);
827
//            releaseWithoutStop();
828
            if (mMediaController != null) mMediaController.hide();
829
//            release(true);
830
            releaseWithoutStop();
831
        }
832
    };
833
834
    public void releaseWithoutStop() {
835
        if (mMediaPlayer != null){
836
            Log.i(TAG, "releaseWithoutStop");
837
            mMediaPlayer.setSurface(null);
838
        }
839
    }
840
841
    /*
842
     * release the media player in any state
843
     */
844
    public void release(boolean cleartargetstate) {
845
846
        if (mMediaPlayer != null) {
847
            Log.i(TAG, "release:" + cleartargetstate);
848
            mMediaPlayer.reset();
849
            mMediaPlayer.release();
850
//            mHandler.removeMessages(MSG_CACHE_DRU);
851
//            monitorRecorder.endRecode();
852
            mMediaPlayer = null;
853
            // REMOVED: mPendingSubtitleTracks.clear();
854
            mCurrentState = STATE_IDLE;
855
            if (cleartargetstate) {
856
                mTargetState = STATE_IDLE;
857
            }
858
            AudioManager am = (AudioManager) mAppContext.getSystemService(Context.AUDIO_SERVICE);
859
            am.abandonAudioFocus(null);
860
        }
861
    }
862
863
    @Override
864
    public boolean onTouchEvent(MotionEvent ev) {
865
        if (isInPlaybackState() && mMediaController != null) {
866
            toggleMediaControlsVisiblity();
867
        }
868
        return false;
869
    }
870
871
    @Override
872
    public boolean onTrackballEvent(MotionEvent ev) {
873
        if (isInPlaybackState() && mMediaController != null) {
874
            toggleMediaControlsVisiblity();
875
        }
876
        return false;
877
    }
878
879
    @Override
880
    public boolean onKeyDown(int keyCode, KeyEvent event) {
881
        boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK &&
882
                keyCode != KeyEvent.KEYCODE_VOLUME_UP &&
883
                keyCode != KeyEvent.KEYCODE_VOLUME_DOWN &&
884
                keyCode != KeyEvent.KEYCODE_VOLUME_MUTE &&
885
                keyCode != KeyEvent.KEYCODE_MENU &&
886
                keyCode != KeyEvent.KEYCODE_CALL &&
887
                keyCode != KeyEvent.KEYCODE_ENDCALL;
888
        if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) {
889
            if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK ||
890
                    keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE) {
891
                if (mMediaPlayer.isPlaying()) {
892
                    pause();
893
                    mMediaController.show();
894
                } else {
895
                    start();
896
                    mMediaController.hide();
897
                }
898
                return true;
899
            } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
900
                if (!mMediaPlayer.isPlaying()) {
901
                    start();
902
                    mMediaController.hide();
903
                }
904
                return true;
905
            } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
906
                    || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
907
                if (mMediaPlayer.isPlaying()) {
908
                    pause();
909
                    mMediaController.show();
910
                }
911
                return true;
912
            } else {
913
                toggleMediaControlsVisiblity();
914
            }
915
        }
916
917
        return super.onKeyDown(keyCode, event);
918
    }
919
920
    private void toggleMediaControlsVisiblity() {
921
        if (mMediaController.isShowing()) {
922
            mMediaController.hide();
923
        } else {
924
            mMediaController.show();
925
        }
926
    }
927
928
    @Override
929
    public void start() {
930
        Log.i(TAG, "start");
931
        if (isInPlaybackState()) {
932
            Log.i(TAG, "start isInPlaybackState");
933
            mMediaPlayer.start();
934
            mCurrentState = STATE_PLAYING;
935
            mRenderView.getView().setBackgroundDrawable(null);
936
        } else {
937
            Log.i(TAG, "start isInPlaybackState false mMediaPlayer == null:" + (mMediaPlayer == null) + " mCurrentState" + mCurrentState);
938
        }
939
        mTargetState = STATE_PLAYING;
940
    }
941
942
    @Override
943
    public void pause() {
944
        if (isInPlaybackState()) {
945
            if (mMediaPlayer.isPlaying()) {
946
                mMediaPlayer.pause();
947
                mCurrentState = STATE_PAUSED;
948
            }
949
        }
950
        mTargetState = STATE_PAUSED;
951
    }
952
953
    public void suspend() {
954
        release(false);
955
    }
956
957
    public void resume() {
958
        openVideo();
959
    }
960
961
    @Override
962
    public int getDuration() {
963
        if (isInPlaybackState()) {
964
            return (int) mMediaPlayer.getDuration();
965
        }
966
967
        return -1;
968
    }
969
970
    @Override
971
    public int getCurrentPosition() {
972
        if (isInPlaybackState()) {
973
            if (mCurrentState == STATE_PLAYBACK_COMPLETED) {
974
                return (int) mMediaPlayer.getDuration();
975
            }
976
            return (int) mMediaPlayer.getCurrentPosition();
977
        }
978
        return 0;
979
    }
980
981
    @Override
982
    public void seekTo(int msec) {
983
        if (isInPlaybackState()) {
984
            mSeekStartTime = System.currentTimeMillis();
985
            mMediaPlayer.seekTo(msec);
986
            mSeekWhenPrepared = 0;
987
        } else {
988
            mSeekWhenPrepared = msec;
989
        }
990
    }
991
992
    @Override
993
    public boolean isPlaying() {
994
        return isInPlaybackState() && mMediaPlayer.isPlaying();
995
    }
996
997
    @Override
998
    public int getBufferPercentage() {
999
        if (mMediaPlayer != null) {
1000
            return mCurrentBufferPercentage;
1001
        }
1002
        return 0;
1003
    }
1004
1005
    private boolean isInPlaybackState() {
1006
        return (mMediaPlayer != null &&
1007
                mCurrentState != STATE_ERROR &&
1008
                mCurrentState != STATE_IDLE &&
1009
                mCurrentState != STATE_PREPARING);
1010
    }
1011
1012
    @Override
1013
    public boolean canPause() {
1014
        return mCanPause;
1015
    }
1016
1017
    @Override
1018
    public boolean canSeekBackward() {
1019
        return mCanSeekBack;
1020
    }
1021
1022
    @Override
1023
    public boolean canSeekForward() {
1024
        return mCanSeekForward;
1025
    }
1026
1027
    @Override
1028
    public int getAudioSessionId() {
1029
        return mMediaPlayer.getAudioSessionId();
1030
    }
1031
1032
    // REMOVED: getAudioSessionId();
1033
    // REMOVED: onAttachedToWindow();
1034
    // REMOVED: onDetachedFromWindow();
1035
    // REMOVED: onLayout();
1036
    // REMOVED: draw();
1037
    // REMOVED: measureAndLayoutSubtitleWidget();
1038
    // REMOVED: setSubtitleWidget();
1039
    // REMOVED: getSubtitleLooper();
1040
    //-------------------------
1041
    // Extend: Aspect Ratio
1042
    //-------------------------
1043
1044
    private static final int[] s_allAspectRatio = {
1045
            IRenderView.AR_ASPECT_FIT_PARENT,
1046
            IRenderView.AR_ASPECT_FILL_PARENT,
1047
            IRenderView.AR_ASPECT_WRAP_CONTENT,
1048
            IRenderView.AR_MATCH_PARENT,
1049
            IRenderView.AR_16_9_FIT_PARENT,
1050
            IRenderView.AR_4_3_FIT_PARENT};
1051
    private int mCurrentAspectRatioIndex = 0;
1052
    private int mCurrentAspectRatio = s_allAspectRatio[0];
1053
1054
    public int toggleAspectRatio() {
1055
        mCurrentAspectRatioIndex++;
1056
        mCurrentAspectRatioIndex %= s_allAspectRatio.length;
1057
1058
        mCurrentAspectRatio = s_allAspectRatio[mCurrentAspectRatioIndex];
1059
        if (mRenderView != null)
1060
            mRenderView.setAspectRatio(mCurrentAspectRatio);
1061
        return mCurrentAspectRatio;
1062
    }
1063
1064
    public void setAspectRatio(int aspectRatio) {
1065
        mCurrentAspectRatio = aspectRatio;
1066
        if (mRenderView != null)
1067
            mRenderView.setAspectRatio(mCurrentAspectRatio);
1068
    }
1069
1070
    public ITrackInfo[] getTrackInfo() {
1071
        if (mMediaPlayer == null)
1072
            return null;
1073
1074
        return mMediaPlayer.getTrackInfo();
1075
    }
1076
1077
    public void selectTrack(int stream) {
1078
        MediaPlayerCompat.selectTrack(mMediaPlayer, stream);
1079
    }
1080
1081
    public void deselectTrack(int stream) {
1082
        MediaPlayerCompat.deselectTrack(mMediaPlayer, stream);
1083
    }
1084
1085
    public int getSelectedTrack(int trackType) {
1086
        return MediaPlayerCompat.getSelectedTrack(mMediaPlayer, trackType);
1087
    }
1088
1089
    public void fullScreen(Activity activity) {
1090
        if (!isFullState) {
1091
            if (activity.getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
1092
                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
1093
            }
1094
            activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
1095
                    WindowManager.LayoutParams.FLAG_FULLSCREEN);
1096
//            DisplayMetrics metrics = new DisplayMetrics();
1097
//            activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
1098
//            mRawParams = getLayoutParams();
1099
//            ViewGroup.LayoutParams fullParams;
1100
//            if (mRawParams instanceof RelativeLayout.LayoutParams) {
1101
//                fullParams = new RelativeLayout.LayoutParams(metrics.widthPixels, metrics.heightPixels);
1102
//            } else if (mRawParams instanceof LinearLayout.LayoutParams) {
1103
//                fullParams = new LinearLayout.LayoutParams(metrics.widthPixels, metrics.heightPixels);
1104
//            } else if (mRawParams instanceof LayoutParams) {
1105
//                fullParams = new LayoutParams(metrics.widthPixels, metrics.heightPixels);
1106
//            } else {
1107
//                new AlertDialog.Builder(getContext())
1108
//                        .setMessage("nonsupport parent layout, please do it by yourself")
1109
//                        .setPositiveButton("OK",
1110
//                                new DialogInterface.OnClickListener() {
1111
//                                    public void onClick(DialogInterface dialog, int whichButton) {
1112
//                                    }
1113
//                                })
1114
//                        .setCancelable(false)
1115
//                        .show();
1116
//                return;
1117
//            }
1118
//            setLayoutParams(fullParams);
1119
            isFullState = true;
1120
        }
1121
    }
1122
1123
    public void exitFullScreen(Activity activity) {
1124
1125
        if (isFullState) {
1126
            if (activity.getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
1127
                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
1128
            }
1129
//            setLayoutParams(mRawParams);
1130
            isFullState = false;
1131
        }
1132
    }
1133
1134
1135
    // TODO: 16/5/20 设置播放前至少缓存时间
1136
    private void setCacheDuration(long cacheDuration) {
1137
        this.cacheDuration = cacheDuration;
1138
    }
1139
1140
    public long cacheDuration;
1141
1142
    /**
1143
     * 设置默认背景图片
1144
     *
1145
     * @param rec
1146
     */
1147
    public void setImage(int rec) {
1148
        if (mRenderView != null) {
1149
            mRenderView.getView().setBackgroundResource(rec);
1150
        }
1151
    }
1152
1153
    public void setImage(Drawable background) {
1154
        if (mRenderView != null) {
1155
            mRenderView.getView().setBackgroundDrawable(background);
1156
        }
1157
    }
1158
1159
    /**
1160
     * 设置缓冲区大小 单位(B) 默认 15MB
1161
     *
1162
     * @param size
1163
     */
1164
    public void setBufferSize(int size) {
1165
        bufferSize = size;
1166
    }
1167
1168
    /**
1169
     * 设置是否自动开始播放 默认false
1170
     *
1171
     * @param autoPlay
1172
     */
1173
    public void setAutoStart(boolean autoPlay) {
1174
        isAutoPlay = autoPlay;
1175
    }
1176
1177
1178
    /**
1179
     * 设置播放速度
1180
     */
1181
    public void setSpeed(float speed) {
1182
        playSpeed = speed;
1183
        if (mMediaPlayer != null) {
1184
            mMediaPlayer.setSpeed(speed);
1185
        }
1186
    }
1187
1188
    public float getSpeed(float speed) {
1189
        if (mMediaPlayer != null) {
1190
            return mMediaPlayer.getSpeed(.0f);
1191
        }
1192
        return .0f;
1193
    }
1194
1195
1196
1197
    private void reportError() {
1198
        Log.e(TAG, "reportError");
1199
        postDelayed(reconnection, 20000);
1200
    }
1201
1202
    private void cancelReport() {
1203
        Log.e(TAG, "cancelReport");
1204
        removeCallbacks(reconnection);
1205
    }
1206
1207
    private Runnable reconnection = new Runnable() {
1208
        @Override
1209
        public void run() {
1210
            release(true);
1211
            mErrorListener.onError(mMediaPlayer, -1001, 0);
1212
        }
1213
    };
1214
}
1215

BIN
app/src/main/res/drawable-xxhdpi/icon_at.png


BIN
app/src/main/res/drawable-xxhdpi/icon_back.png


BIN
app/src/main/res/drawable-xxhdpi/icon_close.png


BIN
app/src/main/res/drawable-xxhdpi/icon_comment.png


BIN
app/src/main/res/drawable-xxhdpi/icon_expend.png


BIN
app/src/main/res/drawable-xxhdpi/icon_forward.png


BIN
app/src/main/res/drawable-xxhdpi/icon_likeed.png


BIN
app/src/main/res/drawable-xxhdpi/icon_more.png


BIN
app/src/main/res/drawable-xxhdpi/icon_write_comment.png


+ 5 - 5
app/src/main/res/layout/activity_videodetails.xml

@ -21,7 +21,6 @@
21 21
            android:layout_width="wrap_content"
22 22
            android:layout_height="wrap_content"
23 23
            android:layout_centerInParent="true"
24
            android:text="待问答问题"
25 24
            android:textColor="#ffffff"
26 25
            android:textSize="18sp" />
27 26
@ -30,18 +29,19 @@
30 29
            android:id="@+id/vd_title_back"
31 30
            android:layout_width="wrap_content"
32 31
            android:layout_height="match_parent"
33
            android:layout_alignParentLeft="true"
32
            android:layout_alignParentStart="true"
34 33
            android:paddingLeft="15dp"
35
            android:paddingRight="15dp"  />
34
            android:paddingRight="15dp"
35
            android:src="@drawable/icon_back" />
36 36
37 37
        <ImageView
38 38
            android:id="@+id/vd_title_dot"
39 39
            android:layout_width="wrap_content"
40 40
            android:layout_height="match_parent"
41
42 41
            android:layout_alignParentRight="true"
43 42
            android:paddingLeft="15dp"
44
            android:paddingRight="15dp" />
43
            android:paddingRight="15dp"
44
            android:src="@drawable/icon_more" />
45 45
46 46
    </RelativeLayout>
47 47
</RelativeLayout>

+ 2 - 2
app/src/main/res/layout/sv_video_publish_info.xml

@ -12,7 +12,7 @@
12 12
        android:layout_alignParentEnd="true"
13 13
        android:layout_marginTop="14dp"
14 14
        android:layout_marginEnd="14dp"
15
        android:background="@drawable/icon_dialog_close" />
15
        android:background="@drawable/icon_close" />
16 16
17 17
18 18
    <LinearLayout
@ -32,7 +32,7 @@
32 32
            android:layout_height="12dp"
33 33
            android:layout_marginStart="12dp"
34 34
            android:layout_marginEnd="4dp"
35
            android:background="#fff" />
35
            android:background="@drawable/icon_at" />
36 36
37 37
        <TextView
38 38
            android:id="@+id/video_publish_topic_con"

+ 32 - 35
app/src/main/res/layout/view_show_bottom.xml

@ -5,22 +5,22 @@
5 5
        android:id="@+id/sv_show_bottom"
6 6
        android:layout_width="match_parent"
7 7
        android:layout_height="50dp"
8
        android:layout_alignParentBottom="true">
8
        android:layout_alignParentBottom="true"
9
        android:background="#000">
9 10
10 11
        <LinearLayout
11 12
            android:id="@+id/sv_show_forward"
12 13
            android:layout_width="wrap_content"
13 14
            android:layout_height="30dp"
14
            android:layout_alignParentRight="true"
15
            android:layout_alignParentEnd="true"
15 16
            android:layout_centerVertical="true"
16
            android:layout_marginRight="15dp"
17
            android:layout_marginEnd="15dp"
17 18
            android:gravity="center_vertical">
18 19
19 20
            <ImageView
20
                android:layout_width="30dp"
21
                android:layout_height="30dp"
22
                android:layout_centerVertical="true"
23
                android:background="#fff" />
21
                android:layout_width="19dp"
22
                android:layout_height="19dp"
23
                android:background="@drawable/icon_forward" />
24 24
25 25
            <TextView
26 26
                android:layout_width="wrap_content"
@ -35,20 +35,20 @@
35 35
            android:layout_width="wrap_content"
36 36
            android:layout_height="30dp"
37 37
            android:layout_centerVertical="true"
38
            android:layout_marginRight="15dp"
38
            android:layout_marginEnd="15dp"
39 39
            android:layout_toStartOf="@+id/sv_show_forward"
40 40
            android:gravity="center_vertical">
41 41
42 42
            <ImageView
43
                android:layout_width="30dp"
44
                android:layout_height="30dp"
45
                android:layout_centerVertical="true"
46
                android:background="#fff" />
43
                android:layout_width="19dp"
44
                android:layout_height="19dp"
45
                android:background="@drawable/icon_comment" />
47 46
48 47
            <TextView
49 48
                android:id="@+id/sv_show_comment_count_tv"
50 49
                android:layout_width="wrap_content"
51 50
                android:layout_height="wrap_content"
51
                android:textColor="#888888"
52 52
                android:textSize="12sp" />
53 53
54 54
        </LinearLayout>
@ -64,15 +64,15 @@
64 64
65 65
            <ImageView
66 66
                android:id="@+id/sv_show_like_img"
67
                android:layout_width="30dp"
68
                android:layout_height="30dp"
69
                android:layout_centerVertical="true"
70
                android:background="#fff" />
67
                android:layout_width="19dp"
68
                android:layout_height="19dp"
69
                android:background="@drawable/icon_likeed" />
71 70
72 71
            <TextView
73 72
                android:id="@+id/sv_show_like_tv"
74 73
                android:layout_width="wrap_content"
75 74
                android:layout_height="wrap_content"
75
                android:textColor="#888888"
76 76
                android:textSize="12sp" />
77 77
78 78
        </LinearLayout>
@ -82,16 +82,15 @@
82 82
            android:layout_width="match_parent"
83 83
            android:layout_height="match_parent"
84 84
            android:layout_centerVertical="true"
85
            android:layout_marginRight="15dp"
85
            android:layout_marginEnd="15dp"
86 86
            android:layout_toStartOf="@+id/sv_show_like_ll"
87 87
            android:gravity="center_vertical">
88 88
89 89
            <ImageView
90
                android:layout_width="30dp"
91
                android:layout_height="30dp"
92
                android:layout_centerVertical="true"
93
                android:layout_marginLeft="15dp"
94
                android:background="#fff" />
90
                android:layout_width="19dp"
91
                android:layout_height="19dp"
92
                android:layout_marginStart="15dp"
93
                android:background="@drawable/icon_write_comment" />
95 94
96 95
            <TextView
97 96
                android:layout_width="wrap_content"
@ -119,24 +118,24 @@
119 118
        android:layout_marginBottom="23dp"
120 119
        android:ellipsize="end"
121 120
        android:maxLines="3"
122
         android:textSize="14sp" />
121
        android:textSize="14sp" />
123 122
124
    <View
123
    <ImageView
125 124
        android:id="@+id/sv_show_tvcon_more"
126 125
        android:layout_width="30dp"
127 126
        android:layout_height="30dp"
128 127
        android:layout_above="@+id/sv_show_bottom"
129 128
        android:layout_alignParentEnd="true"
129
        android:padding="8dp"
130 130
        android:layout_marginBottom="28dp"
131
        android:rotation="90"
132
        android:background="@drawable/ssdk_country_back_arrow" />
131
        android:src="@drawable/icon_expend" />
133 132
134 133
    <RelativeLayout
135 134
        android:id="@+id/sv_show_user_info"
136 135
        android:layout_width="wrap_content"
137 136
        android:layout_height="34dp"
138 137
        android:layout_above="@+id/sv_show_tvcon"
139
        android:layout_marginLeft="15dp"
138
        android:layout_marginStart="15dp"
140 139
        android:layout_marginBottom="5dp">
141 140
142 141
        <ImageView
@ -149,9 +148,8 @@
149 148
            android:id="@+id/sv_show_user_name"
150 149
            android:layout_width="wrap_content"
151 150
            android:layout_height="wrap_content"
152
            android:layout_marginLeft="5dp"
151
            android:layout_marginStart="5dp"
153 152
            android:layout_toEndOf="@+id/sv_show_user_avatar"
154
            android:text="adsdasasdad"
155 153
            android:textColor="#fff"
156 154
            android:textSize="12sp" />
157 155
@ -160,8 +158,7 @@
160 158
            android:layout_width="wrap_content"
161 159
            android:layout_height="wrap_content"
162 160
            android:layout_below="@+id/sv_show_user_name"
163
            android:layout_alignLeft="@+id/sv_show_user_name"
164
            android:text="adsdasasdad"
161
            android:layout_alignStart="@+id/sv_show_user_name"
165 162
            android:textColor="#fff"
166 163
            android:textSize="12sp" />
167 164
    </RelativeLayout>
@ -177,21 +174,21 @@
177 174
        android:background="#b3303030"
178 175
        android:gravity="center_vertical">
179 176
180
        <View
177
        <ImageView
181 178
            android:layout_width="12dp"
182 179
            android:layout_height="12dp"
183 180
            android:layout_marginStart="12dp"
184 181
            android:layout_marginEnd="4dp"
185
            android:background="#fff" />
182
            android:src="@drawable/icon_at" />
186 183
187 184
        <TextView
188 185
            android:id="@+id/sv_show_topic_con"
189 186
            android:layout_width="wrap_content"
190 187
            android:layout_height="wrap_content"
191
            android:layout_marginRight="12dp"
188
            android:layout_marginEnd="12dp"
192 189
            android:ellipsize="end"
193 190
            android:maxLines="1"
194
             android:textColor="#fff"
191
            android:textColor="#fff"
195 192
            android:textSize="11sp" />
196 193
    </LinearLayout>
197 194

+ 5 - 6
app/src/main/res/layout/view_show_comment.xml

@ -15,14 +15,13 @@
15 15
        android:textSize="14sp" />
16 16
17 17
18
    <View
18
    <ImageView
19 19
        android:id="@+id/show_comment_close"
20
        android:layout_width="22dp"
21
        android:layout_height="22dp"
20
        android:layout_width="40dp"
21
        android:layout_height="40dp"
22 22
        android:layout_alignParentEnd="true"
23
        android:layout_marginTop="9dp"
24
        android:layout_marginEnd="14dp"
25
        android:background="@drawable/icon_dialog_close"  />
23
        android:padding="6dp"
24
        android:src="@drawable/icon_close"  />
26 25
27 26
    <View
28 27
        android:layout_width="match_parent"

+ 1 - 0
ijkplayer-java/.gitignore

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

+ 21 - 0
ijkplayer-java/build.gradle

@ -0,0 +1,21 @@
1
apply plugin: 'com.android.library'
2
3
android {
4
5
      compileSdkVersion 26
6
    buildToolsVersion '28.0.3'
7
    defaultConfig {
8
        minSdkVersion 14
9
        targetSdkVersion 26
10
    }
11
    buildTypes {
12
        release {
13
            minifyEnabled false
14
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
15
        }
16
    }
17
}
18
19
dependencies {
20
//    implementation fileTree(dir: 'libs', include: ['*.jar'])
21
}

+ 3 - 0
ijkplayer-java/gradle.properties

@ -0,0 +1,3 @@
1
POM_NAME=ijkplayer-java
2
POM_ARTIFACT_ID=ijkplayer-java
3
POM_PACKAGING=aar

+ 17 - 0
ijkplayer-java/proguard-rules.pro

@ -0,0 +1,17 @@
1
# Add project specific ProGuard rules here.
2
# By default, the flags in this file are appended to flags specified
3
# in /opt/android/ADK/tools/proguard/proguard-android.txt
4
# You can edit the include path and order by changing the proguardFiles
5
# directive in build.gradle.
6
#
7
# For more details, see
8
#   http://developer.android.com/guide/developing/tools/proguard.html
9
10
# Add any project specific keep options here:
11
12
# If your project uses WebView with JS, uncomment the following
13
# and specify the fully qualified class name to the JavaScript interface
14
# class:
15
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16
#   public *;
17
#}

+ 13 - 0
ijkplayer-java/src/androidTest/java/tv/danmaku/ijk/media/player/ApplicationTest.java

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

+ 4 - 0
ijkplayer-java/src/main/AndroidManifest.xml

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

+ 109 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/AbstractMediaPlayer.java

@ -0,0 +1,109 @@
1
/*
2
 * Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package tv.danmaku.ijk.media.player;
18
19
import tv.danmaku.ijk.media.player.misc.IMediaDataSource;
20
21
@SuppressWarnings("WeakerAccess")
22
public abstract class AbstractMediaPlayer implements IMediaPlayer {
23
    private OnPreparedListener mOnPreparedListener;
24
    private OnCompletionListener mOnCompletionListener;
25
    private OnBufferingUpdateListener mOnBufferingUpdateListener;
26
    private OnSeekCompleteListener mOnSeekCompleteListener;
27
    private OnVideoSizeChangedListener mOnVideoSizeChangedListener;
28
    private OnErrorListener mOnErrorListener;
29
    private OnInfoListener mOnInfoListener;
30
31
    public final void setOnPreparedListener(OnPreparedListener listener) {
32
        mOnPreparedListener = listener;
33
    }
34
35
    public final void setOnCompletionListener(OnCompletionListener listener) {
36
        mOnCompletionListener = listener;
37
    }
38
39
    public final void setOnBufferingUpdateListener(
40
            OnBufferingUpdateListener listener) {
41
        mOnBufferingUpdateListener = listener;
42
    }
43
44
    public final void setOnSeekCompleteListener(OnSeekCompleteListener listener) {
45
        mOnSeekCompleteListener = listener;
46
    }
47
48
    public final void setOnVideoSizeChangedListener(
49
            OnVideoSizeChangedListener listener) {
50
        mOnVideoSizeChangedListener = listener;
51
    }
52
53
    public final void setOnErrorListener(OnErrorListener listener) {
54
        mOnErrorListener = listener;
55
    }
56
57
    public final void setOnInfoListener(OnInfoListener listener) {
58
        mOnInfoListener = listener;
59
    }
60
61
    public void resetListeners() {
62
        mOnPreparedListener = null;
63
        mOnBufferingUpdateListener = null;
64
        mOnCompletionListener = null;
65
        mOnSeekCompleteListener = null;
66
        mOnVideoSizeChangedListener = null;
67
        mOnErrorListener = null;
68
        mOnInfoListener = null;
69
    }
70
71
    protected final void notifyOnPrepared() {
72
        if (mOnPreparedListener != null)
73
            mOnPreparedListener.onPrepared(this);
74
    }
75
76
    protected final void notifyOnCompletion() {
77
        if (mOnCompletionListener != null)
78
            mOnCompletionListener.onCompletion(this);
79
    }
80
81
    protected final void notifyOnBufferingUpdate(int percent) {
82
        if (mOnBufferingUpdateListener != null)
83
            mOnBufferingUpdateListener.onBufferingUpdate(this, percent);
84
    }
85
86
    protected final void notifyOnSeekComplete() {
87
        if (mOnSeekCompleteListener != null)
88
            mOnSeekCompleteListener.onSeekComplete(this);
89
    }
90
91
    protected final void notifyOnVideoSizeChanged(int width, int height,
92
                                                  int sarNum, int sarDen) {
93
        if (mOnVideoSizeChangedListener != null)
94
            mOnVideoSizeChangedListener.onVideoSizeChanged(this, width, height,
95
                    sarNum, sarDen);
96
    }
97
98
    protected final boolean notifyOnError(int what, int extra) {
99
        return mOnErrorListener != null && mOnErrorListener.onError(this, what, extra);
100
    }
101
102
    protected final boolean notifyOnInfo(int what, int extra) {
103
        return mOnInfoListener != null && mOnInfoListener.onInfo(this, what, extra);
104
    }
105
106
    public void setDataSource(IMediaDataSource mediaDataSource) {
107
        throw new UnsupportedOperationException();
108
    }
109
}

+ 418 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/AndroidMediaPlayer.java

@ -0,0 +1,418 @@
1
/*
2
 * Copyright (C) 2006 The Android Open Source Project
3
 * Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
package tv.danmaku.ijk.media.player;
19
20
import android.annotation.TargetApi;
21
import android.content.Context;
22
import android.media.AudioManager;
23
import android.media.MediaDataSource;
24
import android.media.MediaPlayer;
25
import android.net.Uri;
26
import android.os.Build;
27
import android.text.TextUtils;
28
import android.view.Surface;
29
import android.view.SurfaceHolder;
30
31
import java.io.FileDescriptor;
32
import java.io.IOException;
33
import java.lang.ref.WeakReference;
34
import java.util.Map;
35
36
import tv.danmaku.ijk.media.player.misc.AndroidTrackInfo;
37
import tv.danmaku.ijk.media.player.misc.IMediaDataSource;
38
import tv.danmaku.ijk.media.player.misc.ITrackInfo;
39
import tv.danmaku.ijk.media.player.pragma.DebugLog;
40
41
public class AndroidMediaPlayer extends AbstractMediaPlayer {
42
    private final MediaPlayer mInternalMediaPlayer;
43
    private final AndroidMediaPlayerListenerHolder mInternalListenerAdapter;
44
    private String mDataSource;
45
    private MediaDataSource mMediaDataSource;
46
47
    private final Object mInitLock = new Object();
48
    private boolean mIsReleased;
49
50
    private static MediaInfo sMediaInfo;
51
52
    public AndroidMediaPlayer() {
53
        synchronized (mInitLock) {
54
            mInternalMediaPlayer = new MediaPlayer();
55
        }
56
        mInternalMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
57
        mInternalListenerAdapter = new AndroidMediaPlayerListenerHolder(this);
58
        attachInternalListeners();
59
    }
60
61
    public MediaPlayer getInternalMediaPlayer() {
62
        return mInternalMediaPlayer;
63
    }
64
65
    @Override
66
    public void setDisplay(SurfaceHolder sh) {
67
        synchronized (mInitLock) {
68
            if (!mIsReleased) {
69
                mInternalMediaPlayer.setDisplay(sh);
70
            }
71
        }
72
    }
73
74
    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
75
    @Override
76
    public void setSurface(Surface surface) {
77
        mInternalMediaPlayer.setSurface(surface);
78
    }
79
80
    @Override
81
    public void setDataSource(Context context, Uri uri)
82
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
83
        mInternalMediaPlayer.setDataSource(context, uri);
84
    }
85
86
    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
87
    @Override
88
    public void setDataSource(Context context, Uri uri, Map<String, String> headers)
89
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
90
        mInternalMediaPlayer.setDataSource(context, uri, headers);
91
    }
92
93
    @Override
94
    public void setDataSource(FileDescriptor fd)
95
            throws IOException, IllegalArgumentException, IllegalStateException {
96
        mInternalMediaPlayer.setDataSource(fd);
97
    }
98
99
    @Override
100
    public void setDataSource(String path) throws IOException,
101
            IllegalArgumentException, SecurityException, IllegalStateException {
102
        mDataSource = path;
103
104
        Uri uri = Uri.parse(path);
105
        String scheme = uri.getScheme();
106
        if (!TextUtils.isEmpty(scheme) && scheme.equalsIgnoreCase("file")) {
107
            mInternalMediaPlayer.setDataSource(uri.getPath());
108
        } else {
109
            mInternalMediaPlayer.setDataSource(path);
110
        }
111
    }
112
113
    @TargetApi(Build.VERSION_CODES.M)
114
    @Override
115
    public void setDataSource(IMediaDataSource mediaDataSource) {
116
        releaseMediaDataSource();
117
118
        mMediaDataSource = new MediaDataSourceProxy(mediaDataSource);
119
        mInternalMediaPlayer.setDataSource(mMediaDataSource);
120
    }
121
122
    @TargetApi(Build.VERSION_CODES.M)
123
    private static class MediaDataSourceProxy extends MediaDataSource {
124
        private final IMediaDataSource mMediaDataSource;
125
126
        public MediaDataSourceProxy(IMediaDataSource mediaDataSource) {
127
            mMediaDataSource = mediaDataSource;
128
        }
129
130
        @Override
131
        public int readAt(long position, byte[] buffer, int offset, int size) throws IOException {
132
            return mMediaDataSource.readAt(position, buffer, offset, size);
133
        }
134
135
        @Override
136
        public long getSize() throws IOException {
137
            return mMediaDataSource.getSize();
138
        }
139
140
        @Override
141
        public void close() throws IOException {
142
            mMediaDataSource.close();
143
        }
144
    }
145
146
    @Override
147
    public String getDataSource() {
148
        return mDataSource;
149
    }
150
151
    private void releaseMediaDataSource() {
152
        if (mMediaDataSource != null) {
153
            try {
154
                mMediaDataSource.close();
155
            } catch (IOException e) {
156
                e.printStackTrace();
157
            }
158
            mMediaDataSource = null;
159
        }
160
    }
161
162
    @Override
163
    public void prepareAsync() throws IllegalStateException {
164
        mInternalMediaPlayer.prepareAsync();
165
    }
166
167
    @Override
168
    public void start() throws IllegalStateException {
169
        mInternalMediaPlayer.start();
170
    }
171
172
    @Override
173
    public void stop() throws IllegalStateException {
174
        mInternalMediaPlayer.stop();
175
    }
176
177
    @Override
178
    public void pause() throws IllegalStateException {
179
        mInternalMediaPlayer.pause();
180
    }
181
182
    @Override
183
    public void setScreenOnWhilePlaying(boolean screenOn) {
184
        mInternalMediaPlayer.setScreenOnWhilePlaying(screenOn);
185
    }
186
187
    @Override
188
    public ITrackInfo[] getTrackInfo() {
189
        return AndroidTrackInfo.fromMediaPlayer(mInternalMediaPlayer);
190
    }
191
192
    @Override
193
    public int getVideoWidth() {
194
        return mInternalMediaPlayer.getVideoWidth();
195
    }
196
197
    @Override
198
    public int getVideoHeight() {
199
        return mInternalMediaPlayer.getVideoHeight();
200
    }
201
202
    @Override
203
    public int getVideoSarNum() {
204
        return 1;
205
    }
206
207
    @Override
208
    public int getVideoSarDen() {
209
        return 1;
210
    }
211
212
    @Override
213
    public boolean isPlaying() {
214
        try {
215
            return mInternalMediaPlayer.isPlaying();
216
        } catch (IllegalStateException e) {
217
            DebugLog.printStackTrace(e);
218
            return false;
219
        }
220
    }
221
222
    @Override
223
    public void seekTo(long msec) throws IllegalStateException {
224
        mInternalMediaPlayer.seekTo((int) msec);
225
    }
226
227
    @Override
228
    public long getCurrentPosition() {
229
        try {
230
            return mInternalMediaPlayer.getCurrentPosition();
231
        } catch (IllegalStateException e) {
232
            DebugLog.printStackTrace(e);
233
            return 0;
234
        }
235
    }
236
237
    @Override
238
    public long getDuration() {
239
        try {
240
            return mInternalMediaPlayer.getDuration();
241
        } catch (IllegalStateException e) {
242
            DebugLog.printStackTrace(e);
243
            return 0;
244
        }
245
    }
246
247
    @Override
248
    public void release() {
249
        mIsReleased = true;
250
        mInternalMediaPlayer.release();
251
        releaseMediaDataSource();
252
        resetListeners();
253
        attachInternalListeners();
254
    }
255
256
    @Override
257
    public void reset() {
258
        try {
259
            mInternalMediaPlayer.reset();
260
        } catch (IllegalStateException e) {
261
            DebugLog.printStackTrace(e);
262
        }
263
        releaseMediaDataSource();
264
        resetListeners();
265
        attachInternalListeners();
266
    }
267
268
    @Override
269
    public void setLooping(boolean looping) {
270
        mInternalMediaPlayer.setLooping(looping);
271
    }
272
273
    @Override
274
    public boolean isLooping() {
275
        return mInternalMediaPlayer.isLooping();
276
    }
277
278
    @Override
279
    public void setVolume(float leftVolume, float rightVolume) {
280
        mInternalMediaPlayer.setVolume(leftVolume, rightVolume);
281
    }
282
283
    @Override
284
    public int getAudioSessionId() {
285
        return mInternalMediaPlayer.getAudioSessionId();
286
    }
287
288
    @Override
289
    public MediaInfo getMediaInfo() {
290
        if (sMediaInfo == null) {
291
            MediaInfo module = new MediaInfo();
292
293
            module.mVideoDecoder = "android";
294
            module.mVideoDecoderImpl = "HW";
295
296
            module.mAudioDecoder = "android";
297
            module.mAudioDecoderImpl = "HW";
298
299
            sMediaInfo = module;
300
        }
301
302
        return sMediaInfo;
303
    }
304
305
    @Override
306
    public void setLogEnabled(boolean enable) {
307
    }
308
309
    @Override
310
    public boolean isPlayable() {
311
        return true;
312
    }
313
314
    /*--------------------
315
     * misc
316
     */
317
    @Override
318
    public void setWakeMode(Context context, int mode) {
319
        mInternalMediaPlayer.setWakeMode(context, mode);
320
    }
321
322
    @Override
323
    public void setAudioStreamType(int streamtype) {
324
        mInternalMediaPlayer.setAudioStreamType(streamtype);
325
    }
326
327
    @Override
328
    public void setKeepInBackground(boolean keepInBackground) {
329
    }
330
331
    /*--------------------
332
     * Listeners adapter
333
     */
334
    private void attachInternalListeners() {
335
        mInternalMediaPlayer.setOnPreparedListener(mInternalListenerAdapter);
336
        mInternalMediaPlayer
337
                .setOnBufferingUpdateListener(mInternalListenerAdapter);
338
        mInternalMediaPlayer.setOnCompletionListener(mInternalListenerAdapter);
339
        mInternalMediaPlayer
340
                .setOnSeekCompleteListener(mInternalListenerAdapter);
341
        mInternalMediaPlayer
342
                .setOnVideoSizeChangedListener(mInternalListenerAdapter);
343
        mInternalMediaPlayer.setOnErrorListener(mInternalListenerAdapter);
344
        mInternalMediaPlayer.setOnInfoListener(mInternalListenerAdapter);
345
    }
346
347
    private class AndroidMediaPlayerListenerHolder implements
348
            MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener,
349
            MediaPlayer.OnBufferingUpdateListener,
350
            MediaPlayer.OnSeekCompleteListener,
351
            MediaPlayer.OnVideoSizeChangedListener,
352
            MediaPlayer.OnErrorListener, MediaPlayer.OnInfoListener {
353
        public final WeakReference<AndroidMediaPlayer> mWeakMediaPlayer;
354
355
        public AndroidMediaPlayerListenerHolder(AndroidMediaPlayer mp) {
356
            mWeakMediaPlayer = new WeakReference<AndroidMediaPlayer>(mp);
357
        }
358
359
        @Override
360
        public boolean onInfo(MediaPlayer mp, int what, int extra) {
361
            AndroidMediaPlayer self = mWeakMediaPlayer.get();
362
            return self != null && notifyOnInfo(what, extra);
363
364
        }
365
366
        @Override
367
        public boolean onError(MediaPlayer mp, int what, int extra) {
368
            AndroidMediaPlayer self = mWeakMediaPlayer.get();
369
            return self != null && notifyOnError(what, extra);
370
371
        }
372
373
        @Override
374
        public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
375
            AndroidMediaPlayer self = mWeakMediaPlayer.get();
376
            if (self == null)
377
                return;
378
379
            notifyOnVideoSizeChanged(width, height, 1, 1);
380
        }
381
382
        @Override
383
        public void onSeekComplete(MediaPlayer mp) {
384
            AndroidMediaPlayer self = mWeakMediaPlayer.get();
385
            if (self == null)
386
                return;
387
388
            notifyOnSeekComplete();
389
        }
390
391
        @Override
392
        public void onBufferingUpdate(MediaPlayer mp, int percent) {
393
            AndroidMediaPlayer self = mWeakMediaPlayer.get();
394
            if (self == null)
395
                return;
396
397
            notifyOnBufferingUpdate(percent);
398
        }
399
400
        @Override
401
        public void onCompletion(MediaPlayer mp) {
402
            AndroidMediaPlayer self = mWeakMediaPlayer.get();
403
            if (self == null)
404
                return;
405
406
            notifyOnCompletion();
407
        }
408
409
        @Override
410
        public void onPrepared(MediaPlayer mp) {
411
            AndroidMediaPlayer self = mWeakMediaPlayer.get();
412
            if (self == null)
413
                return;
414
415
            notifyOnPrepared();
416
        }
417
    }
418
}

+ 200 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IMediaPlayer.java

@ -0,0 +1,200 @@
1
/*
2
 * Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package tv.danmaku.ijk.media.player;
18
19
import android.annotation.TargetApi;
20
import android.content.Context;
21
import android.net.Uri;
22
import android.os.Build;
23
import android.view.Surface;
24
import android.view.SurfaceHolder;
25
26
import java.io.FileDescriptor;
27
import java.io.IOException;
28
import java.util.Map;
29
30
import tv.danmaku.ijk.media.player.misc.IMediaDataSource;
31
import tv.danmaku.ijk.media.player.misc.ITrackInfo;
32
33
public interface IMediaPlayer {
34
    /*
35
     * Do not change these values without updating their counterparts in native
36
     */
37
    int MEDIA_INFO_UNKNOWN = 1;
38
    int MEDIA_INFO_STARTED_AS_NEXT = 2;
39
    int MEDIA_INFO_VIDEO_RENDERING_START = 3;
40
    int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700;
41
    int MEDIA_INFO_BUFFERING_START = 701;
42
    int MEDIA_INFO_BUFFERING_END = 702;
43
    int MEDIA_INFO_NETWORK_BANDWIDTH = 703;
44
    int MEDIA_INFO_BAD_INTERLEAVING = 800;
45
    int MEDIA_INFO_NOT_SEEKABLE = 801;
46
    int MEDIA_INFO_METADATA_UPDATE = 802;
47
    int MEDIA_INFO_TIMED_TEXT_ERROR = 900;
48
    int MEDIA_INFO_UNSUPPORTED_SUBTITLE = 901;
49
    int MEDIA_INFO_SUBTITLE_TIMED_OUT = 902;
50
51
    int MEDIA_INFO_VIDEO_ROTATION_CHANGED = 10001;
52
    int MEDIA_INFO_AUDIO_RENDERING_START = 10002;
53
54
    int MEDIA_ERROR_UNKNOWN = 1;
55
    int MEDIA_ERROR_SERVER_DIED = 100;
56
    int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200;
57
    int MEDIA_ERROR_IO = -1004;
58
    int MEDIA_ERROR_MALFORMED = -1007;
59
    int MEDIA_ERROR_UNSUPPORTED = -1010;
60
    int MEDIA_ERROR_TIMED_OUT = -110;
61
62
    void setDisplay(SurfaceHolder sh);
63
64
    void setDataSource(Context context, Uri uri)
65
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
66
67
    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
68
    void setDataSource(Context context, Uri uri, Map<String, String> headers)
69
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
70
71
    void setDataSource(FileDescriptor fd)
72
            throws IOException, IllegalArgumentException, IllegalStateException;
73
74
    void setDataSource(String path)
75
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
76
77
    String getDataSource();
78
79
    void prepareAsync() throws IllegalStateException;
80
81
    void start() throws IllegalStateException;
82
83
    void stop() throws IllegalStateException;
84
85
    void pause() throws IllegalStateException;
86
87
    void setScreenOnWhilePlaying(boolean screenOn);
88
89
    int getVideoWidth();
90
91
    int getVideoHeight();
92
93
    boolean isPlaying();
94
95
    void seekTo(long msec) throws IllegalStateException;
96
97
    long getCurrentPosition();
98
99
    long getDuration();
100
101
    void release();
102
103
    void reset();
104
105
    void setVolume(float leftVolume, float rightVolume);
106
107
    int getAudioSessionId();
108
109
    MediaInfo getMediaInfo();
110
111
    @SuppressWarnings("EmptyMethod")
112
    @Deprecated
113
    void setLogEnabled(boolean enable);
114
115
    @Deprecated
116
    boolean isPlayable();
117
118
    void setOnPreparedListener(OnPreparedListener listener);
119
120
    void setOnCompletionListener(OnCompletionListener listener);
121
122
    void setOnBufferingUpdateListener(
123
            OnBufferingUpdateListener listener);
124
125
    void setOnSeekCompleteListener(
126
            OnSeekCompleteListener listener);
127
128
    void setOnVideoSizeChangedListener(
129
            OnVideoSizeChangedListener listener);
130
131
    void setOnErrorListener(OnErrorListener listener);
132
133
    void setOnInfoListener(OnInfoListener listener);
134
135
    /*--------------------
136
     * Listeners
137
     */
138
    interface OnPreparedListener {
139
        void onPrepared(IMediaPlayer mp);
140
    }
141
142
    interface OnCompletionListener {
143
        void onCompletion(IMediaPlayer mp);
144
    }
145
146
    interface OnBufferingUpdateListener {
147
        void onBufferingUpdate(IMediaPlayer mp, int percent);
148
    }
149
150
    interface OnSeekCompleteListener {
151
        void onSeekComplete(IMediaPlayer mp);
152
    }
153
154
    interface OnVideoSizeChangedListener {
155
        void onVideoSizeChanged(IMediaPlayer mp, int width, int height,
156
                                int sar_num, int sar_den);
157
    }
158
159
    interface OnErrorListener {
160
        boolean onError(IMediaPlayer mp, int what, int extra);
161
    }
162
163
    interface OnInfoListener {
164
        boolean onInfo(IMediaPlayer mp, int what, int extra);
165
    }
166
167
    /*--------------------
168
     * Optional
169
     */
170
    void setAudioStreamType(int streamtype);
171
172
    @Deprecated
173
    void setKeepInBackground(boolean keepInBackground);
174
175
    int getVideoSarNum();
176
177
    int getVideoSarDen();
178
179
    @Deprecated
180
    void setWakeMode(Context context, int mode);
181
182
    void setLooping(boolean looping);
183
184
    boolean isLooping();
185
186
    /*--------------------
187
     * AndroidMediaPlayer: JELLY_BEAN
188
     */
189
    ITrackInfo[] getTrackInfo();
190
191
    /*--------------------
192
     * AndroidMediaPlayer: ICE_CREAM_SANDWICH:
193
     */
194
    void setSurface(Surface surface);
195
196
    /*--------------------
197
     * AndroidMediaPlayer: M:
198
     */
199
    void setDataSource(IMediaDataSource mediaDataSource);
200
}

+ 27 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/ISurfaceTextureHolder.java

@ -0,0 +1,27 @@
1
/*
2
 * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package tv.danmaku.ijk.media.player;
18
19
import android.graphics.SurfaceTexture;
20
21
public interface ISurfaceTextureHolder {
22
    void setSurfaceTexture(SurfaceTexture surfaceTexture);
23
24
    SurfaceTexture getSurfaceTexture();
25
26
    void setSurfaceTextureHost(ISurfaceTextureHost surfaceTextureHost);
27
}

+ 23 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/ISurfaceTextureHost.java

@ -0,0 +1,23 @@
1
/*
2
 * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package tv.danmaku.ijk.media.player;
18
19
import android.graphics.SurfaceTexture;
20
21
public interface ISurfaceTextureHost {
22
    void releaseSurfaceTexture(SurfaceTexture surfaceTexture);
23
}

+ 22 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkLibLoader.java

@ -0,0 +1,22 @@
1
/*
2
 * Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package tv.danmaku.ijk.media.player;
18
19
public interface IjkLibLoader {
20
    void loadLibrary(String libName) throws UnsatisfiedLinkError,
21
            SecurityException;
22
}

+ 293 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaCodecInfo.java

@ -0,0 +1,293 @@
1
package tv.danmaku.ijk.media.player;
2
3
import android.annotation.TargetApi;
4
import android.media.MediaCodecInfo;
5
import android.media.MediaCodecInfo.CodecCapabilities;
6
import android.media.MediaCodecInfo.CodecProfileLevel;
7
import android.os.Build;
8
import android.text.TextUtils;
9
import android.util.Log;
10
11
import java.util.Locale;
12
import java.util.Map;
13
import java.util.TreeMap;
14
15
public class IjkMediaCodecInfo {
16
    private final static String TAG = "IjkMediaCodecInfo";
17
18
    public static int RANK_MAX = 1000;
19
    public static final int RANK_TESTED = 800;
20
    public static final int RANK_ACCEPTABLE = 700;
21
    public static final int RANK_LAST_CHANCE = 600;
22
    public static final int RANK_SECURE = 300;
23
    public static final int RANK_SOFTWARE = 200;
24
    public static final int RANK_NON_STANDARD = 100;
25
    public static final int RANK_NO_SENSE = 0;
26
27
    public MediaCodecInfo mCodecInfo;
28
    public int mRank = 0;
29
    public String mMimeType;
30
31
    private static Map<String, Integer> sKnownCodecList;
32
33
    private static synchronized Map<String, Integer> getKnownCodecList() {
34
        if (sKnownCodecList != null)
35
            return sKnownCodecList;
36
37
        sKnownCodecList = new TreeMap<String, Integer>(
38
                String.CASE_INSENSITIVE_ORDER);
39
40
        // ----- Nvidia -----
41
        // Tegra3
42
        // Nexus 7 (2012)
43
        // Tegra K1
44
        // Nexus 9
45
        sKnownCodecList.put("OMX.Nvidia.h264.decode", RANK_TESTED);
46
        sKnownCodecList.put("OMX.Nvidia.h264.decode.secure", RANK_SECURE);
47
48
        // ----- Intel -----
49
        // Atom Z3735
50
        // Teclast X98 Air
51
        sKnownCodecList.put("OMX.Intel.hw_vd.h264", RANK_TESTED + 1);
52
        // Atom Z2560
53
        // Dell Venue 7 3730
54
        sKnownCodecList.put("OMX.Intel.VideoDecoder.AVC", RANK_TESTED);
55
56
        // ----- Qualcomm -----
57
        // MSM8260
58
        // Xiaomi MI 1S
59
        sKnownCodecList.put("OMX.qcom.video.decoder.avc", RANK_TESTED);
60
        sKnownCodecList.put("OMX.ittiam.video.decoder.avc", RANK_NO_SENSE);
61
62
        // ----- Samsung -----
63
        // Exynos 3110
64
        // Nexus S
65
        sKnownCodecList.put("OMX.SEC.avc.dec", RANK_TESTED);
66
        sKnownCodecList.put("OMX.SEC.AVC.Decoder", RANK_TESTED - 1);
67
        // OMX.SEC.avcdec doesn't reorder output pictures on GT-9100
68
        sKnownCodecList.put("OMX.SEC.avcdec", RANK_TESTED - 2);
69
        sKnownCodecList.put("OMX.SEC.avc.sw.dec", RANK_SOFTWARE);
70
        // Exynos 5 ?
71
        sKnownCodecList.put("OMX.Exynos.avc.dec", RANK_TESTED);
72
        sKnownCodecList.put("OMX.Exynos.AVC.Decoder", RANK_TESTED - 1);
73
74
        // ------ Huawei hisilicon ------
75
        // Kirin 910, Mali 450 MP
76
        // Huawei HONOR 3C (H30-L01)
77
        sKnownCodecList.put("OMX.k3.video.decoder.avc", RANK_TESTED);
78
        // Kirin 920, Mali T624
79
        // Huawei HONOR 6
80
        sKnownCodecList.put("OMX.IMG.MSVDX.Decoder.AVC", RANK_TESTED);
81
82
        // ----- TI -----
83
        // TI OMAP4460
84
        // Galaxy Nexus
85
        sKnownCodecList.put("OMX.TI.DUCATI1.VIDEO.DECODER", RANK_TESTED);
86
87
        // ------ RockChip ------
88
        // Youku TVBox
89
        sKnownCodecList.put("OMX.rk.video_decoder.avc", RANK_TESTED);
90
91
        // ------ AMLogic -----
92
        // MiBox1, 1s, 2
93
        sKnownCodecList.put("OMX.amlogic.avc.decoder.awesome", RANK_TESTED);
94
95
        // ------ Marvell ------
96
        // Lenovo A788t
97
        sKnownCodecList.put("OMX.MARVELL.VIDEO.HW.CODA7542DECODER", RANK_TESTED);
98
        sKnownCodecList.put("OMX.MARVELL.VIDEO.H264DECODER", RANK_SOFTWARE);
99
100
        // ----- TODO: need test -----
101
        sKnownCodecList.remove("OMX.Action.Video.Decoder");
102
        sKnownCodecList.remove("OMX.allwinner.video.decoder.avc");
103
        sKnownCodecList.remove("OMX.BRCM.vc4.decoder.avc");
104
        sKnownCodecList.remove("OMX.brcm.video.h264.hw.decoder");
105
        sKnownCodecList.remove("OMX.brcm.video.h264.decoder");
106
        sKnownCodecList.remove("OMX.cosmo.video.decoder.avc");
107
        sKnownCodecList.remove("OMX.duos.h264.decoder");
108
        sKnownCodecList.remove("OMX.hantro.81x0.video.decoder");
109
        sKnownCodecList.remove("OMX.hantro.G1.video.decoder");
110
        sKnownCodecList.remove("OMX.hisi.video.decoder");
111
        sKnownCodecList.remove("OMX.LG.decoder.video.avc");
112
        sKnownCodecList.remove("OMX.MS.AVC.Decoder");
113
        sKnownCodecList.remove("OMX.RENESAS.VIDEO.DECODER.H264");
114
        sKnownCodecList.remove("OMX.RTK.video.decoder");
115
        sKnownCodecList.remove("OMX.sprd.h264.decoder");
116
        sKnownCodecList.remove("OMX.ST.VFM.H264Dec");
117
        sKnownCodecList.remove("OMX.vpu.video_decoder.avc");
118
        sKnownCodecList.remove("OMX.WMT.decoder.avc");
119
120
        // Really ?
121
        sKnownCodecList.remove("OMX.bluestacks.hw.decoder");
122
123
        // ---------------
124
        // Useless codec
125
        // ----- google -----
126
        sKnownCodecList.put("OMX.google.h264.decoder", RANK_SOFTWARE);
127
        sKnownCodecList.put("OMX.google.h264.lc.decoder", RANK_SOFTWARE);
128
        // ----- huawei k920 -----
129
        sKnownCodecList.put("OMX.k3.ffmpeg.decoder", RANK_SOFTWARE);
130
        sKnownCodecList.put("OMX.ffmpeg.video.decoder", RANK_SOFTWARE);
131
        // ----- unknown -----
132
        sKnownCodecList.put("OMX.sprd.soft.h264.decoder", RANK_SOFTWARE);
133
134
        return sKnownCodecList;
135
    }
136
137
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
138
    public static IjkMediaCodecInfo setupCandidate(MediaCodecInfo codecInfo,
139
            String mimeType) {
140
        if (codecInfo == null
141
                || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
142
            return null;
143
144
        String name = codecInfo.getName();
145
        if (TextUtils.isEmpty(name))
146
            return null;
147
148
        name = name.toLowerCase(Locale.US);
149
        int rank = RANK_NO_SENSE;
150
        if (!name.startsWith("omx.")) {
151
            rank = RANK_NON_STANDARD;
152
        } else if (name.startsWith("omx.pv")) {
153
            rank = RANK_SOFTWARE;
154
        } else if (name.startsWith("omx.google.")) {
155
            rank = RANK_SOFTWARE;
156
        } else if (name.startsWith("omx.ffmpeg.")) {
157
            rank = RANK_SOFTWARE;
158
        } else if (name.startsWith("omx.k3.ffmpeg.")) {
159
            rank = RANK_SOFTWARE;
160
        } else if (name.startsWith("omx.avcodec.")) {
161
            rank = RANK_SOFTWARE;
162
        } else if (name.startsWith("omx.ittiam.")) {
163
            // unknown codec in qualcomm SoC
164
            rank = RANK_NO_SENSE;
165
        } else if (name.startsWith("omx.mtk.")) {
166
            // 1. MTK only works on 4.3 and above
167
            // 2. MTK works on MIUI 6 (4.2.1)
168
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2)
169
                rank = RANK_NO_SENSE;
170
            else
171
                rank = RANK_TESTED;
172
        } else {
173
            Integer knownRank = getKnownCodecList().get(name);
174
            if (knownRank != null) {
175
                rank = knownRank;
176
            } else {
177
                try {
178
                    CodecCapabilities cap = codecInfo
179
                            .getCapabilitiesForType(mimeType);
180
                    if (cap != null)
181
                        rank = RANK_ACCEPTABLE;
182
                    else
183
                        rank = RANK_LAST_CHANCE;
184
                } catch (Throwable e) {
185
                    rank = RANK_LAST_CHANCE;
186
                }
187
            }
188
        }
189
190
        IjkMediaCodecInfo candidate = new IjkMediaCodecInfo();
191
        candidate.mCodecInfo = codecInfo;
192
        candidate.mRank = rank;
193
        candidate.mMimeType = mimeType;
194
        return candidate;
195
    }
196
197
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
198
    public void dumpProfileLevels(String mimeType) {
199
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
200
            return;
201
202
        try {
203
            CodecCapabilities caps = mCodecInfo
204
                    .getCapabilitiesForType(mimeType);
205
            int maxProfile = 0;
206
            int maxLevel = 0;
207
            if (caps != null) {
208
                if (caps.profileLevels != null) {
209
                    for (CodecProfileLevel profileLevel : caps.profileLevels) {
210
                        if (profileLevel == null)
211
                            continue;
212
213
                        maxProfile = Math.max(maxProfile, profileLevel.profile);
214
                        maxLevel = Math.max(maxLevel, profileLevel.level);
215
                    }
216
                }
217
            }
218
219
            Log.i(TAG,
220
                    String.format(Locale.US, "%s",
221
                            getProfileLevelName(maxProfile, maxLevel)));
222
        } catch (Throwable e) {
223
            Log.i(TAG, "profile-level: exception");
224
        }
225
    }
226
227
    public static String getProfileLevelName(int profile, int level) {
228
        return String.format(Locale.US, " %s Profile Level %s (%d,%d)",
229
                getProfileName(profile), getLevelName(level), profile, level);
230
    }
231
232
    public static String getProfileName(int profile) {
233
        switch (profile) {
234
        case CodecProfileLevel.AVCProfileBaseline:
235
            return "Baseline";
236
        case CodecProfileLevel.AVCProfileMain:
237
            return "Main";
238
        case CodecProfileLevel.AVCProfileExtended:
239
            return "Extends";
240
        case CodecProfileLevel.AVCProfileHigh:
241
            return "High";
242
        case CodecProfileLevel.AVCProfileHigh10:
243
            return "High10";
244
        case CodecProfileLevel.AVCProfileHigh422:
245
            return "High422";
246
        case CodecProfileLevel.AVCProfileHigh444:
247
            return "High444";
248
        default:
249
            return "Unknown";
250
        }
251
    }
252
253
    public static String getLevelName(int level) {
254
        switch (level) {
255
        case CodecProfileLevel.AVCLevel1:
256
            return "1";
257
        case CodecProfileLevel.AVCLevel1b:
258
            return "1b";
259
        case CodecProfileLevel.AVCLevel11:
260
            return "11";
261
        case CodecProfileLevel.AVCLevel12:
262
            return "12";
263
        case CodecProfileLevel.AVCLevel13:
264
            return "13";
265
        case CodecProfileLevel.AVCLevel2:
266
            return "2";
267
        case CodecProfileLevel.AVCLevel21:
268
            return "21";
269
        case CodecProfileLevel.AVCLevel22:
270
            return "22";
271
        case CodecProfileLevel.AVCLevel3:
272
            return "3";
273
        case CodecProfileLevel.AVCLevel31:
274
            return "31";
275
        case CodecProfileLevel.AVCLevel32:
276
            return "32";
277
        case CodecProfileLevel.AVCLevel4:
278
            return "4";
279
        case CodecProfileLevel.AVCLevel41:
280
            return "41";
281
        case CodecProfileLevel.AVCLevel42:
282
            return "42";
283
        case CodecProfileLevel.AVCLevel5:
284
            return "5";
285
        case CodecProfileLevel.AVCLevel51:
286
            return "51";
287
        case 65536: // CodecProfileLevel.AVCLevel52:
288
            return "52";
289
        default:
290
            return "0";
291
        }
292
    }
293
}

+ 380 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaMeta.java

@ -0,0 +1,380 @@
1
package tv.danmaku.ijk.media.player;
2
3
import android.os.Bundle;
4
import android.text.TextUtils;
5
6
import java.util.ArrayList;
7
import java.util.Locale;
8
9
@SuppressWarnings("SameParameterValue")
10
public class IjkMediaMeta {
11
    // media meta
12
    public static final String IJKM_KEY_FORMAT = "format";
13
    public static final String IJKM_KEY_DURATION_US = "duration_us";
14
    public static final String IJKM_KEY_START_US = "start_us";
15
    public static final String IJKM_KEY_BITRATE = "bitrate";
16
    public static final String IJKM_KEY_VIDEO_STREAM = "video";
17
    public static final String IJKM_KEY_AUDIO_STREAM = "audio";
18
19
    // stream meta
20
    public static final String IJKM_KEY_TYPE = "type";
21
    public static final String IJKM_VAL_TYPE__VIDEO = "video";
22
    public static final String IJKM_VAL_TYPE__AUDIO = "audio";
23
    public static final String IJKM_VAL_TYPE__UNKNOWN = "unknown";
24
    public static final String IJKM_KEY_LANGUAGE = "language";
25
26
    public static final String IJKM_KEY_CODEC_NAME = "codec_name";
27
    public static final String IJKM_KEY_CODEC_PROFILE = "codec_profile";
28
    public static final String IJKM_KEY_CODEC_LEVEL = "codec_level";
29
    public static final String IJKM_KEY_CODEC_LONG_NAME = "codec_long_name";
30
    public static final String IJKM_KEY_CODEC_PIXEL_FORMAT = "codec_pixel_format";
31
32
    // stream: video
33
    public static final String IJKM_KEY_WIDTH = "width";
34
    public static final String IJKM_KEY_HEIGHT = "height";
35
    public static final String IJKM_KEY_FPS_NUM = "fps_num";
36
    public static final String IJKM_KEY_FPS_DEN = "fps_den";
37
    public static final String IJKM_KEY_TBR_NUM = "tbr_num";
38
    public static final String IJKM_KEY_TBR_DEN = "tbr_den";
39
    public static final String IJKM_KEY_SAR_NUM = "sar_num";
40
    public static final String IJKM_KEY_SAR_DEN = "sar_den";
41
    // stream: audio
42
    public static final String IJKM_KEY_SAMPLE_RATE = "sample_rate";
43
    public static final String IJKM_KEY_CHANNEL_LAYOUT = "channel_layout";
44
45
    public static final String IJKM_KEY_STREAMS = "streams";
46
47
    public static final long AV_CH_FRONT_LEFT = 0x00000001;
48
    public static final long AV_CH_FRONT_RIGHT = 0x00000002;
49
    public static final long AV_CH_FRONT_CENTER = 0x00000004;
50
    public static final long AV_CH_LOW_FREQUENCY = 0x00000008;
51
    public static final long AV_CH_BACK_LEFT = 0x00000010;
52
    public static final long AV_CH_BACK_RIGHT = 0x00000020;
53
    public static final long AV_CH_FRONT_LEFT_OF_CENTER = 0x00000040;
54
    public static final long AV_CH_FRONT_RIGHT_OF_CENTER = 0x00000080;
55
    public static final long AV_CH_BACK_CENTER = 0x00000100;
56
    public static final long AV_CH_SIDE_LEFT = 0x00000200;
57
    public static final long AV_CH_SIDE_RIGHT = 0x00000400;
58
    public static final long AV_CH_TOP_CENTER = 0x00000800;
59
    public static final long AV_CH_TOP_FRONT_LEFT = 0x00001000;
60
    public static final long AV_CH_TOP_FRONT_CENTER = 0x00002000;
61
    public static final long AV_CH_TOP_FRONT_RIGHT = 0x00004000;
62
    public static final long AV_CH_TOP_BACK_LEFT = 0x00008000;
63
    public static final long AV_CH_TOP_BACK_CENTER = 0x00010000;
64
    public static final long AV_CH_TOP_BACK_RIGHT = 0x00020000;
65
    public static final long AV_CH_STEREO_LEFT = 0x20000000;
66
    public static final long AV_CH_STEREO_RIGHT = 0x40000000;
67
    public static final long AV_CH_WIDE_LEFT = 0x0000000080000000L;
68
    public static final long AV_CH_WIDE_RIGHT = 0x0000000100000000L;
69
    public static final long AV_CH_SURROUND_DIRECT_LEFT = 0x0000000200000000L;
70
    public static final long AV_CH_SURROUND_DIRECT_RIGHT = 0x0000000400000000L;
71
    public static final long AV_CH_LOW_FREQUENCY_2 = 0x0000000800000000L;
72
73
    public static final long AV_CH_LAYOUT_MONO = (AV_CH_FRONT_CENTER);
74
    public static final long AV_CH_LAYOUT_STEREO = (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT);
75
    public static final long AV_CH_LAYOUT_2POINT1 = (AV_CH_LAYOUT_STEREO | AV_CH_LOW_FREQUENCY);
76
    public static final long AV_CH_LAYOUT_2_1 = (AV_CH_LAYOUT_STEREO | AV_CH_BACK_CENTER);
77
    public static final long AV_CH_LAYOUT_SURROUND = (AV_CH_LAYOUT_STEREO | AV_CH_FRONT_CENTER);
78
    public static final long AV_CH_LAYOUT_3POINT1 = (AV_CH_LAYOUT_SURROUND | AV_CH_LOW_FREQUENCY);
79
    public static final long AV_CH_LAYOUT_4POINT0 = (AV_CH_LAYOUT_SURROUND | AV_CH_BACK_CENTER);
80
    public static final long AV_CH_LAYOUT_4POINT1 = (AV_CH_LAYOUT_4POINT0 | AV_CH_LOW_FREQUENCY);
81
    public static final long AV_CH_LAYOUT_2_2 = (AV_CH_LAYOUT_STEREO
82
            | AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT);
83
    public static final long AV_CH_LAYOUT_QUAD = (AV_CH_LAYOUT_STEREO
84
            | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT);
85
    public static final long AV_CH_LAYOUT_5POINT0 = (AV_CH_LAYOUT_SURROUND
86
            | AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT);
87
    public static final long AV_CH_LAYOUT_5POINT1 = (AV_CH_LAYOUT_5POINT0 | AV_CH_LOW_FREQUENCY);
88
    public static final long AV_CH_LAYOUT_5POINT0_BACK = (AV_CH_LAYOUT_SURROUND
89
            | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT);
90
    public static final long AV_CH_LAYOUT_5POINT1_BACK = (AV_CH_LAYOUT_5POINT0_BACK | AV_CH_LOW_FREQUENCY);
91
    public static final long AV_CH_LAYOUT_6POINT0 = (AV_CH_LAYOUT_5POINT0 | AV_CH_BACK_CENTER);
92
    public static final long AV_CH_LAYOUT_6POINT0_FRONT = (AV_CH_LAYOUT_2_2
93
            | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER);
94
    public static final long AV_CH_LAYOUT_HEXAGONAL = (AV_CH_LAYOUT_5POINT0_BACK | AV_CH_BACK_CENTER);
95
    public static final long AV_CH_LAYOUT_6POINT1 = (AV_CH_LAYOUT_5POINT1 | AV_CH_BACK_CENTER);
96
    public static final long AV_CH_LAYOUT_6POINT1_BACK = (AV_CH_LAYOUT_5POINT1_BACK | AV_CH_BACK_CENTER);
97
    public static final long AV_CH_LAYOUT_6POINT1_FRONT = (AV_CH_LAYOUT_6POINT0_FRONT | AV_CH_LOW_FREQUENCY);
98
    public static final long AV_CH_LAYOUT_7POINT0 = (AV_CH_LAYOUT_5POINT0
99
            | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT);
100
    public static final long AV_CH_LAYOUT_7POINT0_FRONT = (AV_CH_LAYOUT_5POINT0
101
            | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER);
102
    public static final long AV_CH_LAYOUT_7POINT1 = (AV_CH_LAYOUT_5POINT1
103
            | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT);
104
    public static final long AV_CH_LAYOUT_7POINT1_WIDE = (AV_CH_LAYOUT_5POINT1
105
            | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER);
106
    public static final long AV_CH_LAYOUT_7POINT1_WIDE_BACK = (AV_CH_LAYOUT_5POINT1_BACK
107
            | AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER);
108
    public static final long AV_CH_LAYOUT_OCTAGONAL = (AV_CH_LAYOUT_5POINT0
109
            | AV_CH_BACK_LEFT | AV_CH_BACK_CENTER | AV_CH_BACK_RIGHT);
110
    public static final long AV_CH_LAYOUT_STEREO_DOWNMIX = (AV_CH_STEREO_LEFT | AV_CH_STEREO_RIGHT);
111
112
    public Bundle mMediaMeta;
113
114
    public String mFormat;
115
    public long mDurationUS;
116
    public long mStartUS;
117
    public long mBitrate;
118
119
    public final ArrayList<IjkStreamMeta> mStreams = new ArrayList<IjkStreamMeta>();
120
    public IjkStreamMeta mVideoStream;
121
    public IjkStreamMeta mAudioStream;
122
123
    public String getString(String key) {
124
        return mMediaMeta.getString(key);
125
    }
126
127
    public int getInt(String key) {
128
        return getInt(key, 0);
129
    }
130
131
    public int getInt(String key, int defaultValue) {
132
        String value = getString(key);
133
        if (TextUtils.isEmpty(value))
134
            return defaultValue;
135
136
        try {
137
            return Integer.parseInt(value);
138
        } catch (NumberFormatException e) {
139
            return defaultValue;
140
        }
141
    }
142
143
    public long getLong(String key) {
144
        return getLong(key, 0);
145
    }
146
147
    public long getLong(String key, long defaultValue) {
148
        String value = getString(key);
149
        if (TextUtils.isEmpty(value))
150
            return defaultValue;
151
152
        try {
153
            return Long.parseLong(value);
154
        } catch (NumberFormatException e) {
155
            return defaultValue;
156
        }
157
    }
158
159
    public ArrayList<Bundle> getParcelableArrayList(String key) {
160
        return mMediaMeta.getParcelableArrayList(key);
161
    }
162
163
    public String getDurationInline() {
164
        long duration = mDurationUS + 5000;
165
        long secs = duration / 1000000;
166
        long mins = secs / 60;
167
        secs %= 60;
168
        long hours = mins / 60;
169
        mins %= 60;
170
        return String.format(Locale.US, "%02d:%02d:%02d", hours, mins, secs);
171
    }
172
173
    public static IjkMediaMeta parse(Bundle mediaMeta) {
174
        if (mediaMeta == null)
175
            return null;
176
177
        IjkMediaMeta meta = new IjkMediaMeta();
178
        meta.mMediaMeta = mediaMeta;
179
180
        meta.mFormat = meta.getString(IJKM_KEY_FORMAT);
181
        meta.mDurationUS = meta.getLong(IJKM_KEY_DURATION_US);
182
        meta.mStartUS = meta.getLong(IJKM_KEY_START_US);
183
        meta.mBitrate = meta.getLong(IJKM_KEY_BITRATE);
184
185
        int videoStreamIndex = meta.getInt(IJKM_KEY_VIDEO_STREAM, -1);
186
        int audioStreamIndex = meta.getInt(IJKM_KEY_AUDIO_STREAM, -1);
187
188
        ArrayList<Bundle> streams = meta
189
                .getParcelableArrayList(IJKM_KEY_STREAMS);
190
        if (streams == null)
191
            return meta;
192
193
        int index = -1;
194
        for (Bundle streamBundle : streams) {
195
            index++;
196
197
            if (streamBundle == null) {
198
                continue;
199
            }
200
201
            IjkStreamMeta streamMeta = new IjkStreamMeta(index);
202
            streamMeta.mMeta = streamBundle;
203
            streamMeta.mType = streamMeta.getString(IJKM_KEY_TYPE);
204
            streamMeta.mLanguage = streamMeta.getString(IJKM_KEY_LANGUAGE);
205
            if (TextUtils.isEmpty(streamMeta.mType))
206
                continue;
207
208
            streamMeta.mCodecName = streamMeta.getString(IJKM_KEY_CODEC_NAME);
209
            streamMeta.mCodecProfile = streamMeta
210
                    .getString(IJKM_KEY_CODEC_PROFILE);
211
            streamMeta.mCodecLongName = streamMeta
212
                    .getString(IJKM_KEY_CODEC_LONG_NAME);
213
            streamMeta.mBitrate = streamMeta.getInt(IJKM_KEY_BITRATE);
214
215
            if (streamMeta.mType.equalsIgnoreCase(IJKM_VAL_TYPE__VIDEO)) {
216
                streamMeta.mWidth = streamMeta.getInt(IJKM_KEY_WIDTH);
217
                streamMeta.mHeight = streamMeta.getInt(IJKM_KEY_HEIGHT);
218
                streamMeta.mFpsNum = streamMeta.getInt(IJKM_KEY_FPS_NUM);
219
                streamMeta.mFpsDen = streamMeta.getInt(IJKM_KEY_FPS_DEN);
220
                streamMeta.mTbrNum = streamMeta.getInt(IJKM_KEY_TBR_NUM);
221
                streamMeta.mTbrDen = streamMeta.getInt(IJKM_KEY_TBR_DEN);
222
                streamMeta.mSarNum = streamMeta.getInt(IJKM_KEY_SAR_NUM);
223
                streamMeta.mSarDen = streamMeta.getInt(IJKM_KEY_SAR_DEN);
224
225
                if (videoStreamIndex == index) {
226
                    meta.mVideoStream = streamMeta;
227
                }
228
            } else if (streamMeta.mType.equalsIgnoreCase(IJKM_VAL_TYPE__AUDIO)) {
229
                streamMeta.mSampleRate = streamMeta
230
                        .getInt(IJKM_KEY_SAMPLE_RATE);
231
                streamMeta.mChannelLayout = streamMeta
232
                        .getLong(IJKM_KEY_CHANNEL_LAYOUT);
233
234
                if (audioStreamIndex == index) {
235
                    meta.mAudioStream = streamMeta;
236
                }
237
            }
238
            meta.mStreams.add(streamMeta);
239
        }
240
241
        return meta;
242
    }
243
244
    public static class IjkStreamMeta {
245
        public Bundle mMeta;
246
247
        public final int mIndex;
248
        public String mType;
249
        public String mLanguage;
250
251
        // common
252
        public String mCodecName;
253
        public String mCodecProfile;
254
        public String mCodecLongName;
255
        public long mBitrate;
256
257
        // video
258
        public int mWidth;
259
        public int mHeight;
260
        public int mFpsNum;
261
        public int mFpsDen;
262
        public int mTbrNum;
263
        public int mTbrDen;
264
        public int mSarNum;
265
        public int mSarDen;
266
267
        // audio
268
        public int mSampleRate;
269
        public long mChannelLayout;
270
271
        public IjkStreamMeta(int index) {
272
            mIndex = index;
273
        }
274
275
        public String getString(String key) {
276
            return mMeta.getString(key);
277
        }
278
279
        public int getInt(String key) {
280
            return getInt(key, 0);
281
        }
282
283
        public int getInt(String key, int defaultValue) {
284
            String value = getString(key);
285
            if (TextUtils.isEmpty(value))
286
                return defaultValue;
287
288
            try {
289
                return Integer.parseInt(value);
290
            } catch (NumberFormatException e) {
291
                return defaultValue;
292
            }
293
        }
294
295
        public long getLong(String key) {
296
            return getLong(key, 0);
297
        }
298
299
        public long getLong(String key, long defaultValue) {
300
            String value = getString(key);
301
            if (TextUtils.isEmpty(value))
302
                return defaultValue;
303
304
            try {
305
                return Long.parseLong(value);
306
            } catch (NumberFormatException e) {
307
                return defaultValue;
308
            }
309
        }
310
311
        public String getCodecLongNameInline() {
312
            if (!TextUtils.isEmpty(mCodecLongName)) {
313
                return mCodecLongName;
314
            } else if (!TextUtils.isEmpty(mCodecName)) {
315
                return mCodecName;
316
            } else {
317
                return "N/A";
318
            }
319
        }
320
321
        public String getCodecShortNameInline() {
322
            if (!TextUtils.isEmpty(mCodecName)) {
323
                return mCodecName;
324
            } else {
325
                return "N/A";
326
            }
327
        }
328
329
        public String getResolutionInline() {
330
            if (mWidth <= 0 || mHeight <= 0) {
331
                return "N/A";
332
            } else if (mSarNum <= 0 || mSarDen <= 0) {
333
                return String.format(Locale.US, "%d x %d", mWidth, mHeight);
334
            } else {
335
                return String.format(Locale.US, "%d x %d [SAR %d:%d]", mWidth,
336
                        mHeight, mSarNum, mSarDen);
337
            }
338
        }
339
340
        public String getFpsInline() {
341
            if (mFpsNum <= 0 || mFpsDen <= 0) {
342
                return "N/A";
343
            } else {
344
                return String.valueOf(((float) (mFpsNum)) / mFpsDen);
345
            }
346
        }
347
348
        public String getBitrateInline() {
349
            if (mBitrate <= 0) {
350
                return "N/A";
351
            } else if (mBitrate < 1000) {
352
                return String.format(Locale.US, "%d bit/s", mBitrate);
353
            } else {
354
                return String.format(Locale.US, "%d kb/s", mBitrate / 1000);
355
            }
356
        }
357
358
        public String getSampleRateInline() {
359
            if (mSampleRate <= 0) {
360
                return "N/A";
361
            } else {
362
                return String.format(Locale.US, "%d Hz", mSampleRate);
363
            }
364
        }
365
366
        public String getChannelLayoutInline() {
367
            if (mChannelLayout <= 0) {
368
                return "N/A";
369
            } else {
370
                if (mChannelLayout == AV_CH_LAYOUT_MONO) {
371
                    return "mono";
372
                } else if (mChannelLayout == AV_CH_LAYOUT_STEREO) {
373
                    return "stereo";
374
                } else {
375
                    return String.format(Locale.US, "%x", mChannelLayout);
376
                }
377
            }
378
        }
379
    }
380
}

+ 1212 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/IjkMediaPlayer.java

@ -0,0 +1,1212 @@
1
/*
2
 * Copyright (C) 2006 The Android Open Source Project
3
 * Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
package tv.danmaku.ijk.media.player;
19
20
import android.annotation.SuppressLint;
21
import android.annotation.TargetApi;
22
import android.content.ContentResolver;
23
import android.content.Context;
24
import android.content.res.AssetFileDescriptor;
25
import android.graphics.SurfaceTexture;
26
import android.media.MediaCodecInfo;
27
import android.media.MediaCodecList;
28
import android.media.RingtoneManager;
29
import android.net.Uri;
30
import android.os.Build;
31
import android.os.Bundle;
32
import android.os.Handler;
33
import android.os.Looper;
34
import android.os.Message;
35
import android.os.ParcelFileDescriptor;
36
import android.os.PowerManager;
37
import android.provider.Settings;
38
import android.text.TextUtils;
39
import android.util.Log;
40
import android.view.Surface;
41
import android.view.SurfaceHolder;
42
43
import java.io.FileDescriptor;
44
import java.io.FileNotFoundException;
45
import java.io.IOException;
46
import java.lang.ref.WeakReference;
47
import java.lang.reflect.Field;
48
import java.security.InvalidParameterException;
49
import java.util.ArrayList;
50
import java.util.Locale;
51
import java.util.Map;
52
53
import tv.danmaku.ijk.media.player.annotations.AccessedByNative;
54
import tv.danmaku.ijk.media.player.annotations.CalledByNative;
55
import tv.danmaku.ijk.media.player.misc.IMediaDataSource;
56
import tv.danmaku.ijk.media.player.misc.ITrackInfo;
57
import tv.danmaku.ijk.media.player.misc.IjkTrackInfo;
58
import tv.danmaku.ijk.media.player.pragma.DebugLog;
59
60
/**
61
 * @author bbcallen
62
 * 
63
 *         Java wrapper of ffplay.
64
 */
65
public final class IjkMediaPlayer extends AbstractMediaPlayer {
66
    private final static String TAG = IjkMediaPlayer.class.getName();
67
68
    private static final int MEDIA_NOP = 0; // interface test message
69
    private static final int MEDIA_PREPARED = 1;
70
    private static final int MEDIA_PLAYBACK_COMPLETE = 2;
71
    private static final int MEDIA_BUFFERING_UPDATE = 3;
72
    private static final int MEDIA_SEEK_COMPLETE = 4;
73
    private static final int MEDIA_SET_VIDEO_SIZE = 5;
74
    private static final int MEDIA_TIMED_TEXT = 99;
75
    private static final int MEDIA_ERROR = 100;
76
    private static final int MEDIA_INFO = 200;
77
78
    protected static final int MEDIA_SET_VIDEO_SAR = 10001;
79
80
    //----------------------------------------
81
    // options
82
    public static final int IJK_LOG_UNKNOWN = 0;
83
    public static final int IJK_LOG_DEFAULT = 1;
84
85
    public static final int IJK_LOG_VERBOSE = 2;
86
    public static final int IJK_LOG_DEBUG = 3;
87
    public static final int IJK_LOG_INFO = 4;
88
    public static final int IJK_LOG_WARN = 5;
89
    public static final int IJK_LOG_ERROR = 6;
90
    public static final int IJK_LOG_FATAL = 7;
91
    public static final int IJK_LOG_SILENT = 8;
92
93
    public static final int OPT_CATEGORY_FORMAT     = 1;
94
    public static final int OPT_CATEGORY_CODEC      = 2;
95
    public static final int OPT_CATEGORY_SWS        = 3;
96
    public static final int OPT_CATEGORY_PLAYER     = 4;
97
98
    public static final int SDL_FCC_YV12 = 0x32315659; // YV12
99
    public static final int SDL_FCC_RV16 = 0x36315652; // RGB565
100
    public static final int SDL_FCC_RV32 = 0x32335652; // RGBX8888
101
    //----------------------------------------
102
103
    //----------------------------------------
104
    // properties
105
    public static final int PROP_FLOAT_VIDEO_DECODE_FRAMES_PER_SECOND = 10001;
106
    public static final int PROP_FLOAT_VIDEO_OUTPUT_FRAMES_PER_SECOND = 10002;
107
    public static final int FFP_PROP_FLOAT_PLAYBACK_RATE              = 10003;
108
109
    public static final int FFP_PROP_INT64_SELECTED_VIDEO_STREAM      = 20001;
110
    public static final int FFP_PROP_INT64_SELECTED_AUDIO_STREAM      = 20002;
111
112
    public static final int FFP_PROP_INT64_VIDEO_DECODER              = 20003;
113
    public static final int FFP_PROP_INT64_AUDIO_DECODER              = 20004;
114
    public static final int     FFP_PROPV_DECODER_UNKNOWN             = 0;
115
    public static final int     FFP_PROPV_DECODER_AVCODEC             = 1;
116
    public static final int     FFP_PROPV_DECODER_MEDIACODEC          = 2;
117
    public static final int     FFP_PROPV_DECODER_VIDEOTOOLBOX        = 3;
118
    public static final int FFP_PROP_INT64_VIDEO_CACHED_DURATION      = 20005;
119
    public static final int FFP_PROP_INT64_AUDIO_CACHED_DURATION      = 20006;
120
    public static final int FFP_PROP_INT64_VIDEO_CACHED_BYTES         = 20007;
121
    public static final int FFP_PROP_INT64_AUDIO_CACHED_BYTES         = 20008;
122
    public static final int FFP_PROP_INT64_VIDEO_CACHED_PACKETS       = 20009;
123
    public static final int FFP_PROP_INT64_AUDIO_CACHED_PACKETS       = 20010;
124
    public static final int FFP_PROP_INT64_BIT_RATE                   = 20100;
125
    public static final int FFP_PROP_INT64_TCP_SPEED                  = 20200;
126
    public static final int FFP_PROP_INT64_LATEST_SEEK_LOAD_DURATION  = 20300;
127
    //----------------------------------------
128
129
    @AccessedByNative
130
    private long mNativeMediaPlayer;
131
    @AccessedByNative
132
    private long mNativeMediaDataSource;
133
134
    @AccessedByNative
135
    private int mNativeSurfaceTexture;
136
137
    @AccessedByNative
138
    private int mListenerContext;
139
140
    private SurfaceHolder mSurfaceHolder;
141
    private EventHandler mEventHandler;
142
    private PowerManager.WakeLock mWakeLock = null;
143
    private boolean mScreenOnWhilePlaying;
144
    private boolean mStayAwake;
145
146
    private int mVideoWidth;
147
    private int mVideoHeight;
148
    private int mVideoSarNum;
149
    private int mVideoSarDen;
150
151
    private String mDataSource;
152
153
    /**
154
     * Default library loader
155
     * Load them by yourself, if your libraries are not installed at default place.
156
     */
157
    private static final IjkLibLoader sLocalLibLoader = new IjkLibLoader() {
158
        @Override
159
        public void loadLibrary(String libName) throws UnsatisfiedLinkError, SecurityException {
160
            System.loadLibrary(libName);
161
        }
162
    };
163
164
    private static volatile boolean mIsLibLoaded = false;
165
    public static void loadLibrariesOnce(IjkLibLoader libLoader) {
166
        synchronized (IjkMediaPlayer.class) {
167
            if (!mIsLibLoaded) {
168
                if (libLoader == null)
169
                    libLoader = sLocalLibLoader;
170
171
                libLoader.loadLibrary("ijkffmpeg");
172
                libLoader.loadLibrary("ijksdl");
173
                libLoader.loadLibrary("ijkplayer");
174
                mIsLibLoaded = true;
175
            }
176
        }
177
    }
178
179
    private static volatile boolean mIsNativeInitialized = false;
180
    private static void initNativeOnce() {
181
        synchronized (IjkMediaPlayer.class) {
182
            if (!mIsNativeInitialized) {
183
                native_init();
184
                mIsNativeInitialized = true;
185
            }
186
        }
187
    }
188
189
    /**
190
     * Default constructor. Consider using one of the create() methods for
191
     * synchronously instantiating a IjkMediaPlayer from a Uri or resource.
192
     * <p>
193
     * When done with the IjkMediaPlayer, you should call {@link #release()}, to
194
     * free the resources. If not released, too many IjkMediaPlayer instances
195
     * may result in an exception.
196
     * </p>
197
     */
198
    public IjkMediaPlayer() {
199
        this(sLocalLibLoader);
200
    }
201
202
    /**
203
     * do not loadLibaray
204
     * @param libLoader
205
     *              custom library loader, can be null.
206
     */
207
    public IjkMediaPlayer(IjkLibLoader libLoader) {
208
        initPlayer(libLoader);
209
    }
210
211
    private void initPlayer(IjkLibLoader libLoader) {
212
        loadLibrariesOnce(libLoader);
213
        initNativeOnce();
214
215
        Looper looper;
216
        if ((looper = Looper.myLooper()) != null) {
217
            mEventHandler = new EventHandler(this, looper);
218
        } else if ((looper = Looper.getMainLooper()) != null) {
219
            mEventHandler = new EventHandler(this, looper);
220
        } else {
221
            mEventHandler = null;
222
        }
223
224
        /*
225
         * Native setup requires a weak reference to our object. It's easier to
226
         * create it here than in C++.
227
         */
228
        native_setup(new WeakReference<IjkMediaPlayer>(this));
229
    }
230
231
    /*
232
     * Update the IjkMediaPlayer SurfaceTexture. Call after setting a new
233
     * display surface.
234
     */
235
    private native void _setVideoSurface(Surface surface);
236
237
    /**
238
     * Sets the {@link SurfaceHolder} to use for displaying the video portion of
239
     * the media.
240
     * 
241
     * Either a surface holder or surface must be set if a display or video sink
242
     * is needed. Not calling this method or {@link #setSurface(Surface)} when
243
     * playing back a video will result in only the audio track being played. A
244
     * null surface holder or surface will result in only the audio track being
245
     * played.
246
     * 
247
     * @param sh
248
     *            the SurfaceHolder to use for video display
249
     */
250
    @Override
251
    public void setDisplay(SurfaceHolder sh) {
252
        mSurfaceHolder = sh;
253
        Surface surface;
254
        if (sh != null) {
255
            surface = sh.getSurface();
256
        } else {
257
            surface = null;
258
        }
259
        _setVideoSurface(surface);
260
        updateSurfaceScreenOn();
261
    }
262
263
    /**
264
     * Sets the {@link Surface} to be used as the sink for the video portion of
265
     * the media. This is similar to {@link #setDisplay(SurfaceHolder)}, but
266
     * does not support {@link #setScreenOnWhilePlaying(boolean)}. Setting a
267
     * Surface will un-set any Surface or SurfaceHolder that was previously set.
268
     * A null surface will result in only the audio track being played.
269
     * 
270
     * If the Surface sends frames to a {@link SurfaceTexture}, the timestamps
271
     * returned from {@link SurfaceTexture#getTimestamp()} will have an
272
     * unspecified zero point. These timestamps cannot be directly compared
273
     * between different media sources, different instances of the same media
274
     * source, or multiple runs of the same program. The timestamp is normally
275
     * monotonically increasing and is unaffected by time-of-day adjustments,
276
     * but it is reset when the position is set.
277
     * 
278
     * @param surface
279
     *            The {@link Surface} to be used for the video portion of the
280
     *            media.
281
     */
282
    @Override
283
    public void setSurface(Surface surface) {
284
        if (mScreenOnWhilePlaying && surface != null) {
285
            DebugLog.w(TAG,
286
                    "setScreenOnWhilePlaying(true) is ineffective for Surface");
287
        }
288
        mSurfaceHolder = null;
289
        _setVideoSurface(surface);
290
        updateSurfaceScreenOn();
291
    }
292
293
    /**
294
     * Sets the data source as a content Uri.
295
     *
296
     * @param context the Context to use when resolving the Uri
297
     * @param uri the Content URI of the data you want to play
298
     * @throws IllegalStateException if it is called in an invalid state
299
     */
300
    @Override
301
    public void setDataSource(Context context, Uri uri)
302
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
303
        setDataSource(context, uri, null);
304
    }
305
306
    /**
307
     * Sets the data source as a content Uri.
308
     *
309
     * @param context the Context to use when resolving the Uri
310
     * @param uri the Content URI of the data you want to play
311
     * @param headers the headers to be sent together with the request for the data
312
     *                Note that the cross domain redirection is allowed by default, but that can be
313
     *                changed with key/value pairs through the headers parameter with
314
     *                "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value
315
     *                to disallow or allow cross domain redirection.
316
     * @throws IllegalStateException if it is called in an invalid state
317
     */
318
    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
319
    @Override
320
    public void setDataSource(Context context, Uri uri, Map<String, String> headers)
321
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
322
        final String scheme = uri.getScheme();
323
        if (ContentResolver.SCHEME_FILE.equals(scheme)) {
324
            setDataSource(uri.getPath());
325
            return;
326
        } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
327
                && Settings.AUTHORITY.equals(uri.getAuthority())) {
328
            // Redirect ringtones to go directly to underlying provider
329
            uri = RingtoneManager.getActualDefaultRingtoneUri(context,
330
                    RingtoneManager.getDefaultType(uri));
331
            if (uri == null) {
332
                throw new FileNotFoundException("Failed to resolve default ringtone");
333
            }
334
        }
335
336
        AssetFileDescriptor fd = null;
337
        try {
338
            ContentResolver resolver = context.getContentResolver();
339
            fd = resolver.openAssetFileDescriptor(uri, "r");
340
            if (fd == null) {
341
                return;
342
            }
343
            // Note: using getDeclaredLength so that our behavior is the same
344
            // as previous versions when the content provider is returning
345
            // a full file.
346
            if (fd.getDeclaredLength() < 0) {
347
                setDataSource(fd.getFileDescriptor());
348
            } else {
349
                setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getDeclaredLength());
350
            }
351
            return;
352
        } catch (SecurityException ignored) {
353
        } catch (IOException ignored) {
354
        } finally {
355
            if (fd != null) {
356
                fd.close();
357
            }
358
        }
359
360
        Log.d(TAG, "Couldn't open file on client side, trying server side");
361
362
        setDataSource(uri.toString(), headers);
363
    }
364
365
    /**
366
     * Sets the data source (file-path or http/rtsp URL) to use.
367
     * 
368
     * @param path
369
     *            the path of the file, or the http/rtsp URL of the stream you
370
     *            want to play
371
     * @throws IllegalStateException
372
     *             if it is called in an invalid state
373
     * 
374
     *             <p>
375
     *             When <code>path</code> refers to a local file, the file may
376
     *             actually be opened by a process other than the calling
377
     *             application. This implies that the pathname should be an
378
     *             absolute path (as any other process runs with unspecified
379
     *             current working directory), and that the pathname should
380
     *             reference a world-readable file.
381
     */
382
    @Override
383
    public void setDataSource(String path)
384
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
385
        mDataSource = path;
386
        _setDataSource(path, null, null);
387
    }
388
389
    /**
390
     * Sets the data source (file-path or http/rtsp URL) to use.
391
     *
392
     * @param path the path of the file, or the http/rtsp URL of the stream you want to play
393
     * @param headers the headers associated with the http request for the stream you want to play
394
     * @throws IllegalStateException if it is called in an invalid state
395
     */
396
    public void setDataSource(String path, Map<String, String> headers)
397
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException
398
    {
399
        if (headers != null && !headers.isEmpty()) {
400
            StringBuilder sb = new StringBuilder();
401
            for(Map.Entry<String, String> entry: headers.entrySet()) {
402
                sb.append(entry.getKey());
403
                sb.append(":");
404
                String value = entry.getValue();
405
                if (!TextUtils.isEmpty(value))
406
                    sb.append(entry.getValue());
407
                sb.append("\r\n");
408
                setOption(OPT_CATEGORY_FORMAT, "headers", sb.toString());
409
            }
410
        }
411
        setDataSource(path);
412
    }
413
414
    /**
415
     * Sets the data source (FileDescriptor) to use. It is the caller's responsibility
416
     * to close the file descriptor. It is safe to do so as soon as this call returns.
417
     *
418
     * @param fd the FileDescriptor for the file you want to play
419
     * @throws IllegalStateException if it is called in an invalid state
420
     */
421
    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
422
    @Override
423
    public void setDataSource(FileDescriptor fd)
424
            throws IOException, IllegalArgumentException, IllegalStateException {
425
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR1) {
426
            int native_fd = -1;
427
            try {
428
                Field f = fd.getClass().getDeclaredField("descriptor"); //NoSuchFieldException
429
                f.setAccessible(true);
430
                native_fd = f.getInt(fd); //IllegalAccessException
431
            } catch (NoSuchFieldException e) {
432
                throw new RuntimeException(e);
433
            } catch (IllegalAccessException e) {
434
                throw new RuntimeException(e);
435
            }
436
            _setDataSourceFd(native_fd);
437
        } else {
438
            ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(fd);
439
            try {
440
                _setDataSourceFd(pfd.getFd());
441
            } finally {
442
                pfd.close();
443
            }
444
        }
445
    }
446
447
    /**
448
     * Sets the data source (FileDescriptor) to use.  The FileDescriptor must be
449
     * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility
450
     * to close the file descriptor. It is safe to do so as soon as this call returns.
451
     *
452
     * @param fd the FileDescriptor for the file you want to play
453
     * @param offset the offset into the file where the data to be played starts, in bytes
454
     * @param length the length in bytes of the data to be played
455
     * @throws IllegalStateException if it is called in an invalid state
456
     */
457
    private void setDataSource(FileDescriptor fd, long offset, long length)
458
            throws IOException, IllegalArgumentException, IllegalStateException {
459
        // FIXME: handle offset, length
460
        setDataSource(fd);
461
    }
462
463
    public void setDataSource(IMediaDataSource mediaDataSource)
464
            throws IllegalArgumentException, SecurityException, IllegalStateException {
465
        _setDataSource(mediaDataSource);
466
    }
467
468
    private native void _setDataSource(String path, String[] keys, String[] values)
469
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
470
471
    private native void _setDataSourceFd(int fd)
472
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
473
474
    private native void _setDataSource(IMediaDataSource mediaDataSource)
475
            throws IllegalArgumentException, SecurityException, IllegalStateException;
476
477
    @Override
478
    public String getDataSource() {
479
        return mDataSource;
480
    }
481
482
    @Override
483
    public void prepareAsync() throws IllegalStateException {
484
        _prepareAsync();
485
    }
486
487
    public native void _prepareAsync() throws IllegalStateException;
488
489
    @Override
490
    public void start() throws IllegalStateException {
491
        stayAwake(true);
492
        _start();
493
    }
494
495
    private native void _start() throws IllegalStateException;
496
497
    @Override
498
    public void stop() throws IllegalStateException {
499
        stayAwake(false);
500
        _stop();
501
    }
502
503
    private native void _stop() throws IllegalStateException;
504
505
    @Override
506
    public void pause() throws IllegalStateException {
507
        stayAwake(false);
508
        _pause();
509
    }
510
511
    private native void _pause() throws IllegalStateException;
512
513
    @SuppressLint("Wakelock")
514
    @Override
515
    public void setWakeMode(Context context, int mode) {
516
        boolean washeld = false;
517
        if (mWakeLock != null) {
518
            if (mWakeLock.isHeld()) {
519
                washeld = true;
520
                mWakeLock.release();
521
            }
522
            mWakeLock = null;
523
        }
524
525
        PowerManager pm = (PowerManager) context
526
                .getSystemService(Context.POWER_SERVICE);
527
        mWakeLock = pm.newWakeLock(mode | PowerManager.ON_AFTER_RELEASE,
528
                IjkMediaPlayer.class.getName());
529
        mWakeLock.setReferenceCounted(false);
530
        if (washeld) {
531
            mWakeLock.acquire();
532
        }
533
    }
534
535
    @Override
536
    public void setScreenOnWhilePlaying(boolean screenOn) {
537
        if (mScreenOnWhilePlaying != screenOn) {
538
            if (screenOn && mSurfaceHolder == null) {
539
                DebugLog.w(TAG,
540
                        "setScreenOnWhilePlaying(true) is ineffective without a SurfaceHolder");
541
            }
542
            mScreenOnWhilePlaying = screenOn;
543
            updateSurfaceScreenOn();
544
        }
545
    }
546
547
    @SuppressLint("Wakelock")
548
    private void stayAwake(boolean awake) {
549
        if (mWakeLock != null) {
550
            if (awake && !mWakeLock.isHeld()) {
551
                mWakeLock.acquire();
552
            } else if (!awake && mWakeLock.isHeld()) {
553
                mWakeLock.release();
554
            }
555
        }
556
        mStayAwake = awake;
557
        updateSurfaceScreenOn();
558
    }
559
560
    private void updateSurfaceScreenOn() {
561
        if (mSurfaceHolder != null) {
562
            mSurfaceHolder.setKeepScreenOn(mScreenOnWhilePlaying && mStayAwake);
563
        }
564
    }
565
566
    @Override
567
    public IjkTrackInfo[] getTrackInfo() {
568
        Bundle bundle = getMediaMeta();
569
        if (bundle == null)
570
            return null;
571
572
        IjkMediaMeta mediaMeta = IjkMediaMeta.parse(bundle);
573
        if (mediaMeta == null || mediaMeta.mStreams == null)
574
            return null;
575
576
        ArrayList<IjkTrackInfo> trackInfos = new ArrayList<IjkTrackInfo>();
577
        for (IjkMediaMeta.IjkStreamMeta streamMeta: mediaMeta.mStreams) {
578
            IjkTrackInfo trackInfo = new IjkTrackInfo(streamMeta);
579
            if (streamMeta.mType.equalsIgnoreCase(IjkMediaMeta.IJKM_VAL_TYPE__VIDEO)) {
580
                trackInfo.setTrackType(ITrackInfo.MEDIA_TRACK_TYPE_VIDEO);
581
            } else if (streamMeta.mType.equalsIgnoreCase(IjkMediaMeta.IJKM_VAL_TYPE__AUDIO)) {
582
                trackInfo.setTrackType(ITrackInfo.MEDIA_TRACK_TYPE_AUDIO);
583
            }
584
            trackInfos.add(trackInfo);
585
        }
586
587
        return trackInfos.toArray(new IjkTrackInfo[trackInfos.size()]);
588
    }
589
590
    // TODO: @Override
591
    public int getSelectedTrack(int trackType) {
592
        switch (trackType) {
593
            case ITrackInfo.MEDIA_TRACK_TYPE_VIDEO:
594
                return (int)_getPropertyLong(FFP_PROP_INT64_SELECTED_VIDEO_STREAM, -1);
595
            case ITrackInfo.MEDIA_TRACK_TYPE_AUDIO:
596
                return (int)_getPropertyLong(FFP_PROP_INT64_SELECTED_AUDIO_STREAM, -1);
597
            default:
598
                return -1;
599
        }
600
    }
601
602
    // experimental, should set DEFAULT_MIN_FRAMES and MAX_MIN_FRAMES to 25
603
    // TODO: @Override
604
    public void selectTrack(int track) {
605
        _setStreamSelected(track, true);
606
    }
607
608
    // experimental, should set DEFAULT_MIN_FRAMES and MAX_MIN_FRAMES to 25
609
    // TODO: @Override
610
    public void deselectTrack(int track) {
611
        _setStreamSelected(track, false);
612
    }
613
614
    private native void _setStreamSelected(int stream, boolean select);
615
616
    @Override
617
    public int getVideoWidth() {
618
        return mVideoWidth;
619
    }
620
621
    @Override
622
    public int getVideoHeight() {
623
        return mVideoHeight;
624
    }
625
626
    @Override
627
    public int getVideoSarNum() {
628
        return mVideoSarNum;
629
    }
630
631
    @Override
632
    public int getVideoSarDen() {
633
        return mVideoSarDen;
634
    }
635
636
    @Override
637
    public native boolean isPlaying();
638
639
    @Override
640
    public native void seekTo(long msec) throws IllegalStateException;
641
642
    @Override
643
    public native long getCurrentPosition();
644
645
    @Override
646
    public native long getDuration();
647
648
    /**
649
     * Releases resources associated with this IjkMediaPlayer object. It is
650
     * considered good practice to call this method when you're done using the
651
     * IjkMediaPlayer. In particular, whenever an Activity of an application is
652
     * paused (its onPause() method is called), or stopped (its onStop() method
653
     * is called), this method should be invoked to release the IjkMediaPlayer
654
     * object, unless the application has a special need to keep the object
655
     * around. In addition to unnecessary resources (such as memory and
656
     * instances of codecs) being held, failure to call this method immediately
657
     * if a IjkMediaPlayer object is no longer needed may also lead to
658
     * continuous battery consumption for mobile devices, and playback failure
659
     * for other applications if no multiple instances of the same codec are
660
     * supported on a device. Even if multiple instances of the same codec are
661
     * supported, some performance degradation may be expected when unnecessary
662
     * multiple instances are used at the same time.
663
     */
664
    @Override
665
    public void release() {
666
        stayAwake(false);
667
        updateSurfaceScreenOn();
668
        resetListeners();
669
        _release();
670
    }
671
672
    private native void _release();
673
674
    @Override
675
    public void reset() {
676
        stayAwake(false);
677
        _reset();
678
        // make sure none of the listeners get called anymore
679
        mEventHandler.removeCallbacksAndMessages(null);
680
681
        mVideoWidth = 0;
682
        mVideoHeight = 0;
683
    }
684
685
    private native void _reset();
686
687
    /**
688
     * Sets the player to be looping or non-looping.
689
     *
690
     * @param looping whether to loop or not
691
     */
692
    @Override
693
    public void setLooping(boolean looping) {
694
        int loopCount = looping ? 0 : 1;
695
        setOption(OPT_CATEGORY_PLAYER, "loop", loopCount);
696
        _setLoopCount(loopCount);
697
    }
698
699
    private native void _setLoopCount(int loopCount);
700
701
    /**
702
     * Checks whether the MediaPlayer is looping or non-looping.
703
     *
704
     * @return true if the MediaPlayer is currently looping, false otherwise
705
     */
706
    @Override
707
    public boolean isLooping() {
708
        int loopCount = _getLoopCount();
709
        return loopCount != 1;
710
    }
711
712
    private native int _getLoopCount();
713
714
    @TargetApi(Build.VERSION_CODES.M)
715
    public void setSpeed(float speed) {
716
        _setPropertyFloat(FFP_PROP_FLOAT_PLAYBACK_RATE, speed);
717
    }
718
719
    @TargetApi(Build.VERSION_CODES.M)
720
    public float getSpeed(float speed) {
721
        return _getPropertyFloat(FFP_PROP_FLOAT_PLAYBACK_RATE, .0f);
722
    }
723
724
    public int getVideoDecoder() {
725
        return (int)_getPropertyLong(FFP_PROP_INT64_VIDEO_DECODER, FFP_PROPV_DECODER_UNKNOWN);
726
    }
727
728
    public float getVideoOutputFramesPerSecond() {
729
        return _getPropertyFloat(PROP_FLOAT_VIDEO_OUTPUT_FRAMES_PER_SECOND, 0.0f);
730
    }
731
732
    public float getVideoDecodeFramesPerSecond() {
733
        return _getPropertyFloat(PROP_FLOAT_VIDEO_DECODE_FRAMES_PER_SECOND, 0.0f);
734
    }
735
736
    public long getVideoCachedDuration() {
737
        return _getPropertyLong(FFP_PROP_INT64_VIDEO_CACHED_DURATION, 0);
738
    }
739
740
    public long getAudioCachedDuration() {
741
        return _getPropertyLong(FFP_PROP_INT64_AUDIO_CACHED_DURATION, 0);
742
    }
743
744
    public long getVideoCachedBytes() {
745
        return _getPropertyLong(FFP_PROP_INT64_VIDEO_CACHED_BYTES, 0);
746
    }
747
748
    public long getAudioCachedBytes() {
749
        return _getPropertyLong(FFP_PROP_INT64_AUDIO_CACHED_BYTES, 0);
750
    }
751
752
    public long getVideoCachedPackets() {
753
        return _getPropertyLong(FFP_PROP_INT64_VIDEO_CACHED_PACKETS, 0);
754
    }
755
756
    public long getAudioCachedPackets() {
757
        return _getPropertyLong(FFP_PROP_INT64_AUDIO_CACHED_PACKETS, 0);
758
    }
759
760
    public long getBitrate() {
761
        return _getPropertyLong(FFP_PROP_INT64_BIT_RATE, 0);
762
    }
763
764
    public long getTcpSpeed() {
765
        return _getPropertyLong(FFP_PROP_INT64_TCP_SPEED, 0);
766
    }
767
768
    public long getSeekLoadDuration() {
769
        return _getPropertyLong(FFP_PROP_INT64_LATEST_SEEK_LOAD_DURATION, 0);
770
    }
771
772
    private native float _getPropertyFloat(int property, float defaultValue);
773
    private native void  _setPropertyFloat(int property, float value);
774
    private native long  _getPropertyLong(int property, long defaultValue);
775
    private native void  _setPropertyLong(int property, long value);
776
777
    @Override
778
    public native void setVolume(float leftVolume, float rightVolume);
779
780
    @Override
781
    public native int getAudioSessionId();
782
783
    @Override
784
    public MediaInfo getMediaInfo() {
785
        MediaInfo mediaInfo = new MediaInfo();
786
        mediaInfo.mMediaPlayerName = "ijkplayer";
787
788
        String videoCodecInfo = _getVideoCodecInfo();
789
        if (!TextUtils.isEmpty(videoCodecInfo)) {
790
            String nodes[] = videoCodecInfo.split(",");
791
            if (nodes.length >= 2) {
792
                mediaInfo.mVideoDecoder = nodes[0];
793
                mediaInfo.mVideoDecoderImpl = nodes[1];
794
            } else if (nodes.length >= 1) {
795
                mediaInfo.mVideoDecoder = nodes[0];
796
                mediaInfo.mVideoDecoderImpl = "";
797
            }
798
        }
799
800
        String audioCodecInfo = _getAudioCodecInfo();
801
        if (!TextUtils.isEmpty(audioCodecInfo)) {
802
            String nodes[] = audioCodecInfo.split(",");
803
            if (nodes.length >= 2) {
804
                mediaInfo.mAudioDecoder = nodes[0];
805
                mediaInfo.mAudioDecoderImpl = nodes[1];
806
            } else if (nodes.length >= 1) {
807
                mediaInfo.mAudioDecoder = nodes[0];
808
                mediaInfo.mAudioDecoderImpl = "";
809
            }
810
        }
811
812
        try {
813
            mediaInfo.mMeta = IjkMediaMeta.parse(_getMediaMeta());
814
        } catch (Throwable e) {
815
            e.printStackTrace();
816
        }
817
        return mediaInfo;
818
    }
819
820
    @Override
821
    public void setLogEnabled(boolean enable) {
822
        // do nothing
823
    }
824
825
    @Override
826
    public boolean isPlayable() {
827
        return true;
828
    }
829
830
    private native String _getVideoCodecInfo();
831
    private native String _getAudioCodecInfo();
832
833
    public void setOption(int category, String name, String value)
834
    {
835
        _setOption(category, name, value);
836
    }
837
838
    public void setOption(int category, String name, long value)
839
    {
840
        _setOption(category, name, value);
841
    }
842
843
    private native void _setOption(int category, String name, String value);
844
    private native void _setOption(int category, String name, long value);
845
846
    public Bundle getMediaMeta() {
847
        return _getMediaMeta();
848
    }
849
    private native Bundle _getMediaMeta();
850
    public native Bundle _getMetaData();
851
852
    public static String getColorFormatName(int mediaCodecColorFormat) {
853
        return _getColorFormatName(mediaCodecColorFormat);
854
    }
855
856
    private static native String _getColorFormatName(int mediaCodecColorFormat);
857
858
    @Override
859
    public void setAudioStreamType(int streamtype) {
860
        // do nothing
861
    }
862
863
    @Override
864
    public void setKeepInBackground(boolean keepInBackground) {
865
        // do nothing
866
    }
867
868
    private static native void native_init();
869
870
    private native void native_setup(Object IjkMediaPlayer_this);
871
872
    private native void native_finalize();
873
874
    private native void native_message_loop(Object IjkMediaPlayer_this);
875
876
    protected void finalize() throws Throwable {
877
        super.finalize();
878
        native_finalize();
879
    }
880
881
    private static class EventHandler extends Handler {
882
        private final WeakReference<IjkMediaPlayer> mWeakPlayer;
883
884
        public EventHandler(IjkMediaPlayer mp, Looper looper) {
885
            super(looper);
886
            mWeakPlayer = new WeakReference<IjkMediaPlayer>(mp);
887
        }
888
889
        @Override
890
        public void handleMessage(Message msg) {
891
            IjkMediaPlayer player = mWeakPlayer.get();
892
            if (player == null || player.mNativeMediaPlayer == 0) {
893
                DebugLog.w(TAG,
894
                        "IjkMediaPlayer went away with unhandled events");
895
                return;
896
            }
897
898
            switch (msg.what) {
899
            case MEDIA_PREPARED:
900
                player.notifyOnPrepared();
901
                return;
902
903
            case MEDIA_PLAYBACK_COMPLETE:
904
                player.stayAwake(false);
905
                player.notifyOnCompletion();
906
                return;
907
908
            case MEDIA_BUFFERING_UPDATE:
909
                long bufferPosition = msg.arg1;
910
                if (bufferPosition < 0) {
911
                    bufferPosition = 0;
912
                }
913
914
                long percent = 0;
915
                long duration = player.getDuration();
916
                if (duration > 0) {
917
                    percent = bufferPosition * 100 / duration;
918
                }
919
                if (percent >= 100) {
920
                    percent = 100;
921
                }
922
923
                // DebugLog.efmt(TAG, "Buffer (%d%%) %d/%d",  percent, bufferPosition, duration);
924
                player.notifyOnBufferingUpdate((int)percent);
925
                return;
926
927
            case MEDIA_SEEK_COMPLETE:
928
                player.notifyOnSeekComplete();
929
                return;
930
931
            case MEDIA_SET_VIDEO_SIZE:
932
                player.mVideoWidth = msg.arg1;
933
                player.mVideoHeight = msg.arg2;
934
                player.notifyOnVideoSizeChanged(player.mVideoWidth, player.mVideoHeight,
935
                        player.mVideoSarNum, player.mVideoSarDen);
936
                return;
937
938
            case MEDIA_ERROR:
939
                DebugLog.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")");
940
                if (!player.notifyOnError(msg.arg1, msg.arg2)) {
941
                    player.notifyOnCompletion();
942
                }
943
                player.stayAwake(false);
944
                return;
945
946
            case MEDIA_INFO:
947
                switch (msg.arg1) {
948
                    case MEDIA_INFO_VIDEO_RENDERING_START:
949
                        DebugLog.i(TAG, "Info: MEDIA_INFO_VIDEO_RENDERING_START\n");
950
                        break;
951
                }
952
                player.notifyOnInfo(msg.arg1, msg.arg2);
953
                // No real default action so far.
954
                return;
955
            case MEDIA_TIMED_TEXT:
956
                // do nothing
957
                break;
958
959
            case MEDIA_NOP: // interface test message - ignore
960
                break;
961
962
            case MEDIA_SET_VIDEO_SAR:
963
                player.mVideoSarNum = msg.arg1;
964
                player.mVideoSarDen = msg.arg2;
965
                player.notifyOnVideoSizeChanged(player.mVideoWidth, player.mVideoHeight,
966
                        player.mVideoSarNum, player.mVideoSarDen);
967
                break;
968
969
            default:
970
                DebugLog.e(TAG, "Unknown message type " + msg.what);
971
            }
972
        }
973
    }
974
975
    /*
976
     * Called from native code when an interesting event happens. This method
977
     * just uses the EventHandler system to post the event back to the main app
978
     * thread. We use a weak reference to the original IjkMediaPlayer object so
979
     * that the native code is safe from the object disappearing from underneath
980
     * it. (This is the cookie passed to native_setup().)
981
     */
982
    @CalledByNative
983
    private static void postEventFromNative(Object weakThiz, int what,
984
            int arg1, int arg2, Object obj) {
985
        if (weakThiz == null)
986
            return;
987
988
        @SuppressWarnings("rawtypes")
989
        IjkMediaPlayer mp = (IjkMediaPlayer) ((WeakReference) weakThiz).get();
990
        if (mp == null) {
991
            return;
992
        }
993
994
        if (what == MEDIA_INFO && arg1 == MEDIA_INFO_STARTED_AS_NEXT) {
995
            // this acquires the wakelock if needed, and sets the client side
996
            // state
997
            mp.start();
998
        }
999
        if (mp.mEventHandler != null) {
1000
            Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);
1001
            mp.mEventHandler.sendMessage(m);
1002
        }
1003
    }
1004
1005
    /*
1006
     * ControlMessage
1007
     */
1008
1009
    private OnControlMessageListener mOnControlMessageListener;
1010
    public void setOnControlMessageListener(OnControlMessageListener listener) {
1011
        mOnControlMessageListener = listener;
1012
    }
1013
1014
    public interface OnControlMessageListener {
1015
        String onControlResolveSegmentUrl(int segment);
1016
    }
1017
1018
    /*
1019
     * NativeInvoke
1020
     */
1021
1022
    private OnNativeInvokeListener mOnNativeInvokeListener;
1023
    public void setOnNativeInvokeListener(OnNativeInvokeListener listener) {
1024
        mOnNativeInvokeListener = listener;
1025
    }
1026
1027
    public interface OnNativeInvokeListener {
1028
        int ON_CONCAT_RESOLVE_SEGMENT = 0x10000;
1029
        int ON_TCP_OPEN = 0x10001;
1030
        int ON_HTTP_OPEN = 0x10002;
1031
        // int ON_HTTP_RETRY = 0x10003;
1032
        int ON_LIVE_RETRY = 0x10004;
1033
1034
        String ARG_URL = "url";
1035
        String ARG_SEGMENT_INDEX = "segment_index";
1036
        String ARG_RETRY_COUNTER = "retry_counter";
1037
1038
        /*
1039
         * @return true if invoke is handled
1040
         * @throws Exception on any error
1041
         */
1042
        boolean onNativeInvoke(int what, Bundle args);
1043
    }
1044
1045
    @CalledByNative
1046
    private static boolean onNativeInvoke(Object weakThiz, int what, Bundle args) {
1047
        DebugLog.ifmt(TAG, "onNativeInvoke %d", what);
1048
        if (weakThiz == null || !(weakThiz instanceof WeakReference<?>))
1049
            throw new IllegalStateException("<null weakThiz>.onNativeInvoke()");
1050
1051
        @SuppressWarnings("unchecked")
1052
        WeakReference<IjkMediaPlayer> weakPlayer = (WeakReference<IjkMediaPlayer>) weakThiz;
1053
        IjkMediaPlayer player = weakPlayer.get();
1054
        if (player == null)
1055
            throw new IllegalStateException("<null weakPlayer>.onNativeInvoke()");
1056
1057
        OnNativeInvokeListener listener = player.mOnNativeInvokeListener;
1058
        if (listener != null && listener.onNativeInvoke(what, args))
1059
            return true;
1060
1061
        switch (what) {
1062
            case OnNativeInvokeListener.ON_CONCAT_RESOLVE_SEGMENT: {
1063
                OnControlMessageListener onControlMessageListener = player.mOnControlMessageListener;
1064
                if (onControlMessageListener == null)
1065
                    return false;
1066
1067
                int segmentIndex = args.getInt(OnNativeInvokeListener.ARG_SEGMENT_INDEX, -1);
1068
                if (segmentIndex < 0)
1069
                    throw new InvalidParameterException("onNativeInvoke(invalid segment index)");
1070
1071
                String newUrl = onControlMessageListener.onControlResolveSegmentUrl(segmentIndex);
1072
                if (newUrl == null)
1073
                    throw new RuntimeException(new IOException("onNativeInvoke() = <NULL newUrl>"));
1074
1075
                args.putString(OnNativeInvokeListener.ARG_URL, newUrl);
1076
                return true;
1077
            }
1078
            default:
1079
                return false;
1080
        }
1081
    }
1082
1083
    /*
1084
     * MediaCodec select
1085
     */
1086
1087
    public interface OnMediaCodecSelectListener {
1088
        String onMediaCodecSelect(IMediaPlayer mp, String mimeType, int profile, int level);
1089
    }
1090
    private OnMediaCodecSelectListener mOnMediaCodecSelectListener;
1091
    public void setOnMediaCodecSelectListener(OnMediaCodecSelectListener listener) {
1092
        mOnMediaCodecSelectListener = listener;
1093
    }
1094
1095
    public void resetListeners() {
1096
        super.resetListeners();
1097
        mOnMediaCodecSelectListener = null;
1098
    }
1099
1100
    @CalledByNative
1101
    private static String onSelectCodec(Object weakThiz, String mimeType, int profile, int level) {
1102
        if (weakThiz == null || !(weakThiz instanceof WeakReference<?>))
1103
            return null;
1104
1105
        @SuppressWarnings("unchecked")
1106
        WeakReference<IjkMediaPlayer> weakPlayer = (WeakReference<IjkMediaPlayer>) weakThiz;
1107
        IjkMediaPlayer player = weakPlayer.get();
1108
        if (player == null)
1109
            return null;
1110
1111
        OnMediaCodecSelectListener listener = player.mOnMediaCodecSelectListener;
1112
        if (listener == null)
1113
            listener = DefaultMediaCodecSelector.sInstance;
1114
1115
        return listener.onMediaCodecSelect(player, mimeType, profile, level);
1116
    }
1117
1118
    public static class DefaultMediaCodecSelector implements OnMediaCodecSelectListener {
1119
        public static final DefaultMediaCodecSelector sInstance = new DefaultMediaCodecSelector();
1120
1121
        @SuppressWarnings("deprecation")
1122
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
1123
        public String onMediaCodecSelect(IMediaPlayer mp, String mimeType, int profile, int level) {
1124
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
1125
                return null;
1126
1127
            if (TextUtils.isEmpty(mimeType))
1128
                return null;
1129
1130
            Log.i(TAG, String.format(Locale.US, "onSelectCodec: mime=%s, profile=%d, level=%d", mimeType, profile, level));
1131
            ArrayList<IjkMediaCodecInfo> candidateCodecList = new ArrayList<IjkMediaCodecInfo>();
1132
            int numCodecs = MediaCodecList.getCodecCount();
1133
            for (int i = 0; i < numCodecs; i++) {
1134
                MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
1135
                Log.d(TAG, String.format(Locale.US, "  found codec: %s", codecInfo.getName()));
1136
                if (codecInfo.isEncoder())
1137
                    continue;
1138
1139
                String[] types = codecInfo.getSupportedTypes();
1140
                if (types == null)
1141
                    continue;
1142
1143
                for(String type: types) {
1144
                    if (TextUtils.isEmpty(type))
1145
                        continue;
1146
1147
                    Log.d(TAG, String.format(Locale.US, "    mime: %s", type));
1148
                    if (!type.equalsIgnoreCase(mimeType))
1149
                        continue;
1150
1151
                    IjkMediaCodecInfo candidate = IjkMediaCodecInfo.setupCandidate(codecInfo, mimeType);
1152
                    if (candidate == null)
1153
                        continue;
1154
1155
                    candidateCodecList.add(candidate);
1156
                    Log.i(TAG, String.format(Locale.US, "candidate codec: %s rank=%d", codecInfo.getName(), candidate.mRank));
1157
                    candidate.dumpProfileLevels(mimeType);
1158
                }
1159
            }
1160
1161
            if (candidateCodecList.isEmpty()) {
1162
                return null;
1163
            }
1164
1165
            IjkMediaCodecInfo bestCodec = candidateCodecList.get(0);
1166
1167
            for (IjkMediaCodecInfo codec : candidateCodecList) {
1168
                if (codec.mRank > bestCodec.mRank) {
1169
                    bestCodec = codec;
1170
                }
1171
            }
1172
1173
            if (bestCodec.mRank < IjkMediaCodecInfo.RANK_LAST_CHANCE) {
1174
                Log.w(TAG, String.format(Locale.US, "unaccetable codec: %s", bestCodec.mCodecInfo.getName()));
1175
                return null;
1176
            }
1177
1178
            Log.i(TAG, String.format(Locale.US, "selected codec: %s rank=%d", bestCodec.mCodecInfo.getName(), bestCodec.mRank));
1179
            return bestCodec.mCodecInfo.getName();
1180
        }
1181
    }
1182
1183
    public static native void native_profileBegin(String libName);
1184
    public static native void native_profileEnd();
1185
    public static native void native_setLogLevel(int level);
1186
1187
    private native void _setAudioDataCallback();
1188
    private native void _delAudioDataCallback();
1189
1190
    private OnAudioDataCallback mAudioDataCallback = null;
1191
1192
    public void setOnAudioDataCallback(OnAudioDataCallback callback) {
1193
        if (callback != null) {
1194
            this.mAudioDataCallback = callback;
1195
            _setAudioDataCallback();
1196
        } else {
1197
            this.mAudioDataCallback = null;
1198
            _delAudioDataCallback();
1199
        }
1200
    }
1201
1202
    public interface OnAudioDataCallback {
1203
        void onAudioData(byte[] audio_data, int len);
1204
    }
1205
1206
    // audio data callback
1207
    public void audioCallback(byte[] audio_data, int data_size) {
1208
        if (mAudioDataCallback != null) {
1209
            mAudioDataCallback.onAudioData(audio_data, data_size);
1210
        }
1211
    }
1212
}

+ 29 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/MediaInfo.java

@ -0,0 +1,29 @@
1
/*
2
 * Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package tv.danmaku.ijk.media.player;
18
19
public class MediaInfo {
20
    public String mMediaPlayerName;
21
22
    public String mVideoDecoder;
23
    public String mVideoDecoderImpl;
24
25
    public String mAudioDecoder;
26
    public String mAudioDecoderImpl;
27
28
    public IjkMediaMeta mMeta;
29
}

+ 323 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/MediaPlayerProxy.java

@ -0,0 +1,323 @@
1
/*
2
 * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package tv.danmaku.ijk.media.player;
18
19
import android.annotation.TargetApi;
20
import android.content.Context;
21
import android.net.Uri;
22
import android.os.Build;
23
import android.view.Surface;
24
import android.view.SurfaceHolder;
25
26
import java.io.FileDescriptor;
27
import java.io.IOException;
28
import java.util.Map;
29
30
import tv.danmaku.ijk.media.player.misc.IMediaDataSource;
31
import tv.danmaku.ijk.media.player.misc.ITrackInfo;
32
33
public class MediaPlayerProxy implements IMediaPlayer {
34
    protected final IMediaPlayer mBackEndMediaPlayer;
35
36
    public MediaPlayerProxy(IMediaPlayer backEndMediaPlayer) {
37
        mBackEndMediaPlayer = backEndMediaPlayer;
38
    }
39
40
    public IMediaPlayer getInternalMediaPlayer() {
41
        return mBackEndMediaPlayer;
42
    }
43
44
    @Override
45
    public void setDisplay(SurfaceHolder sh) {
46
        mBackEndMediaPlayer.setDisplay(sh);
47
    }
48
49
    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
50
    @Override
51
    public void setSurface(Surface surface) {
52
        mBackEndMediaPlayer.setSurface(surface);
53
    }
54
55
    @Override
56
    public void setDataSource(Context context, Uri uri)
57
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
58
        mBackEndMediaPlayer.setDataSource(context, uri);
59
    }
60
61
    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
62
    @Override
63
    public void setDataSource(Context context, Uri uri, Map<String, String> headers)
64
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
65
        mBackEndMediaPlayer.setDataSource(context, uri, headers);
66
    }
67
68
    @Override
69
    public void setDataSource(FileDescriptor fd)
70
            throws IOException, IllegalArgumentException, IllegalStateException {
71
        mBackEndMediaPlayer.setDataSource(fd);
72
    }
73
74
    @Override
75
    public void setDataSource(String path) throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
76
        mBackEndMediaPlayer.setDataSource(path);
77
    }
78
79
    @Override
80
    public void setDataSource(IMediaDataSource mediaDataSource)  {
81
        mBackEndMediaPlayer.setDataSource(mediaDataSource);
82
    }
83
84
    @Override
85
    public String getDataSource() {
86
        return mBackEndMediaPlayer.getDataSource();
87
    }
88
89
    @Override
90
    public void prepareAsync() throws IllegalStateException {
91
        mBackEndMediaPlayer.prepareAsync();
92
    }
93
94
    @Override
95
    public void start() throws IllegalStateException {
96
        mBackEndMediaPlayer.start();
97
    }
98
99
    @Override
100
    public void stop() throws IllegalStateException {
101
        mBackEndMediaPlayer.stop();
102
    }
103
104
    @Override
105
    public void pause() throws IllegalStateException {
106
        mBackEndMediaPlayer.pause();
107
    }
108
109
    @Override
110
    public void setScreenOnWhilePlaying(boolean screenOn) {
111
        mBackEndMediaPlayer.setScreenOnWhilePlaying(screenOn);
112
    }
113
114
    @Override
115
    public int getVideoWidth() {
116
        return mBackEndMediaPlayer.getVideoWidth();
117
    }
118
119
    @Override
120
    public int getVideoHeight() {
121
        return mBackEndMediaPlayer.getVideoHeight();
122
    }
123
124
    @Override
125
    public boolean isPlaying() {
126
        return mBackEndMediaPlayer.isPlaying();
127
    }
128
129
    @Override
130
    public void seekTo(long msec) throws IllegalStateException {
131
        mBackEndMediaPlayer.seekTo(msec);
132
    }
133
134
    @Override
135
    public long getCurrentPosition() {
136
        return mBackEndMediaPlayer.getCurrentPosition();
137
    }
138
139
    @Override
140
    public long getDuration() {
141
        return mBackEndMediaPlayer.getDuration();
142
    }
143
144
    @Override
145
    public void release() {
146
        mBackEndMediaPlayer.release();
147
    }
148
149
    @Override
150
    public void reset() {
151
        mBackEndMediaPlayer.reset();
152
    }
153
154
    @Override
155
    public void setVolume(float leftVolume, float rightVolume) {
156
        mBackEndMediaPlayer.setVolume(leftVolume, rightVolume);
157
    }
158
159
    @Override
160
    public int getAudioSessionId() {
161
        return mBackEndMediaPlayer.getAudioSessionId();
162
    }
163
164
    @Override
165
    public MediaInfo getMediaInfo() {
166
        return mBackEndMediaPlayer.getMediaInfo();
167
    }
168
169
    @Override
170
    public void setLogEnabled(boolean enable) {
171
172
    }
173
174
    @Override
175
    public boolean isPlayable() {
176
        return false;
177
    }
178
179
    @Override
180
    public void setOnPreparedListener(OnPreparedListener listener) {
181
        if (listener != null) {
182
            final OnPreparedListener finalListener = listener;
183
            mBackEndMediaPlayer.setOnPreparedListener(new OnPreparedListener() {
184
                @Override
185
                public void onPrepared(IMediaPlayer mp) {
186
                    finalListener.onPrepared(MediaPlayerProxy.this);
187
                }
188
            });
189
        } else {
190
            mBackEndMediaPlayer.setOnPreparedListener(null);
191
        }
192
    }
193
194
    @Override
195
    public void setOnCompletionListener(OnCompletionListener listener) {
196
        if (listener != null) {
197
            final OnCompletionListener finalListener = listener;
198
            mBackEndMediaPlayer.setOnCompletionListener(new OnCompletionListener() {
199
                @Override
200
                public void onCompletion(IMediaPlayer mp) {
201
                    finalListener.onCompletion(MediaPlayerProxy.this);
202
                }
203
            });
204
        } else {
205
            mBackEndMediaPlayer.setOnCompletionListener(null);
206
        }
207
    }
208
209
    @Override
210
    public void setOnBufferingUpdateListener(OnBufferingUpdateListener listener) {
211
        if (listener != null) {
212
            final OnBufferingUpdateListener finalListener = listener;
213
            mBackEndMediaPlayer.setOnBufferingUpdateListener(new OnBufferingUpdateListener() {
214
                @Override
215
                public void onBufferingUpdate(IMediaPlayer mp, int percent) {
216
                    finalListener.onBufferingUpdate(MediaPlayerProxy.this, percent);
217
                }
218
            });
219
        } else {
220
            mBackEndMediaPlayer.setOnBufferingUpdateListener(null);
221
        }
222
    }
223
224
    @Override
225
    public void setOnSeekCompleteListener(OnSeekCompleteListener listener) {
226
        if (listener != null) {
227
            final OnSeekCompleteListener finalListener = listener;
228
            mBackEndMediaPlayer.setOnSeekCompleteListener(new OnSeekCompleteListener() {
229
                @Override
230
                public void onSeekComplete(IMediaPlayer mp) {
231
                    finalListener.onSeekComplete(MediaPlayerProxy.this);
232
                }
233
            });
234
        } else {
235
            mBackEndMediaPlayer.setOnSeekCompleteListener(null);
236
        }
237
    }
238
239
    @Override
240
    public void setOnVideoSizeChangedListener(OnVideoSizeChangedListener listener) {
241
        if (listener != null) {
242
            final OnVideoSizeChangedListener finalListener = listener;
243
            mBackEndMediaPlayer.setOnVideoSizeChangedListener(new OnVideoSizeChangedListener() {
244
                @Override
245
                public void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sar_num, int sar_den) {
246
                    finalListener.onVideoSizeChanged(MediaPlayerProxy.this, width, height, sar_num, sar_den);
247
                }
248
            });
249
        } else {
250
            mBackEndMediaPlayer.setOnVideoSizeChangedListener(null);
251
        }
252
    }
253
254
    @Override
255
    public void setOnErrorListener(OnErrorListener listener) {
256
        if (listener != null) {
257
            final OnErrorListener finalListener = listener;
258
            mBackEndMediaPlayer.setOnErrorListener(new OnErrorListener() {
259
                @Override
260
                public boolean onError(IMediaPlayer mp, int what, int extra) {
261
                    return finalListener.onError(MediaPlayerProxy.this, what, extra);
262
                }
263
            });
264
        } else {
265
            mBackEndMediaPlayer.setOnErrorListener(null);
266
        }
267
    }
268
269
    @Override
270
    public void setOnInfoListener(OnInfoListener listener) {
271
        if (listener != null) {
272
            final OnInfoListener finalListener = listener;
273
            mBackEndMediaPlayer.setOnInfoListener(new OnInfoListener() {
274
                @Override
275
                public boolean onInfo(IMediaPlayer mp, int what, int extra) {
276
                    return finalListener.onInfo(MediaPlayerProxy.this, what, extra);
277
                }
278
            });
279
        } else {
280
            mBackEndMediaPlayer.setOnInfoListener(null);
281
        }
282
    }
283
284
    @Override
285
    public void setAudioStreamType(int streamtype) {
286
        mBackEndMediaPlayer.setAudioStreamType(streamtype);
287
    }
288
289
    @Override
290
    public void setKeepInBackground(boolean keepInBackground) {
291
        mBackEndMediaPlayer.setKeepInBackground(keepInBackground);
292
    }
293
294
    @Override
295
    public int getVideoSarNum() {
296
        return mBackEndMediaPlayer.getVideoSarNum();
297
    }
298
299
    @Override
300
    public int getVideoSarDen() {
301
        return mBackEndMediaPlayer.getVideoSarDen();
302
    }
303
304
    @Override
305
    public void setWakeMode(Context context, int mode) {
306
        mBackEndMediaPlayer.setWakeMode(context, mode);
307
    }
308
309
    @Override
310
    public ITrackInfo[] getTrackInfo() {
311
        return mBackEndMediaPlayer.getTrackInfo();
312
    }
313
314
    @Override
315
    public void setLooping(boolean looping) {
316
        mBackEndMediaPlayer.setLooping(looping);
317
    }
318
319
    @Override
320
    public boolean isLooping() {
321
        return mBackEndMediaPlayer.isLooping();
322
    }
323
}

+ 99 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/TextureMediaPlayer.java

@ -0,0 +1,99 @@
1
/*
2
 * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package tv.danmaku.ijk.media.player;
18
19
import android.annotation.TargetApi;
20
import android.graphics.SurfaceTexture;
21
import android.os.Build;
22
import android.view.Surface;
23
import android.view.SurfaceHolder;
24
25
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
26
public class TextureMediaPlayer extends MediaPlayerProxy implements IMediaPlayer, ISurfaceTextureHolder {
27
    private SurfaceTexture mSurfaceTexture;
28
    private ISurfaceTextureHost mSurfaceTextureHost;
29
30
    public TextureMediaPlayer(IMediaPlayer backEndMediaPlayer) {
31
        super(backEndMediaPlayer);
32
    }
33
34
    public void releaseSurfaceTexture() {
35
        if (mSurfaceTexture != null) {
36
            if (mSurfaceTextureHost != null) {
37
                mSurfaceTextureHost.releaseSurfaceTexture(mSurfaceTexture);
38
            } else {
39
                mSurfaceTexture.release();
40
            }
41
            mSurfaceTexture = null;
42
        }
43
    }
44
45
    //--------------------
46
    // IMediaPlayer
47
    //--------------------
48
    @Override
49
    public void reset() {
50
        super.reset();
51
        releaseSurfaceTexture();
52
    }
53
54
    @Override
55
    public void release() {
56
        super.release();
57
        releaseSurfaceTexture();
58
    }
59
60
    @Override
61
    public void setDisplay(SurfaceHolder sh) {
62
        if (mSurfaceTexture == null)
63
            super.setDisplay(sh);
64
    }
65
66
    @Override
67
    public void setSurface(Surface surface) {
68
        if (mSurfaceTexture == null)
69
            super.setSurface(surface);
70
    }
71
72
    //--------------------
73
    // ISurfaceTextureHolder
74
    //--------------------
75
76
    @Override
77
    public void setSurfaceTexture(SurfaceTexture surfaceTexture) {
78
        if (mSurfaceTexture == surfaceTexture)
79
            return;
80
81
        releaseSurfaceTexture();
82
        mSurfaceTexture = surfaceTexture;
83
        if (surfaceTexture == null) {
84
            super.setSurface(null);
85
        } else {
86
            super.setSurface(new Surface(surfaceTexture));
87
        }
88
    }
89
90
    @Override
91
    public SurfaceTexture getSurfaceTexture() {
92
        return mSurfaceTexture;
93
    }
94
95
    @Override
96
    public void setSurfaceTextureHost(ISurfaceTextureHost surfaceTextureHost) {
97
        mSurfaceTextureHost = surfaceTextureHost;
98
    }
99
}

+ 31 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/annotations/AccessedByNative.java

@ -0,0 +1,31 @@
1
/*
2
 * Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package tv.danmaku.ijk.media.player.annotations;
18
19
import java.lang.annotation.ElementType;
20
import java.lang.annotation.Retention;
21
import java.lang.annotation.RetentionPolicy;
22
import java.lang.annotation.Target;
23
24
/**
25
 * is used by the JNI generator to create the necessary JNI
26
 * bindings and expose this method to native code.
27
 */
28
@Target(ElementType.FIELD)
29
@Retention(RetentionPolicy.CLASS)
30
public @interface AccessedByNative {
31
}

+ 35 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/annotations/CalledByNative.java

@ -0,0 +1,35 @@
1
/*
2
 * Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package tv.danmaku.ijk.media.player.annotations;
18
19
import java.lang.annotation.ElementType;
20
import java.lang.annotation.Retention;
21
import java.lang.annotation.RetentionPolicy;
22
import java.lang.annotation.Target;
23
24
/**
25
 * is used by the JNI generator to create the necessary JNI
26
 * bindings and expose this method to native code.
27
 */
28
@Target(ElementType.METHOD)
29
@Retention(RetentionPolicy.CLASS)
30
public @interface CalledByNative {
31
    /*
32
     * If present, tells which inner class the method belongs to.
33
     */
34
    String value() default "";
35
}

+ 21 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/exceptions/IjkMediaException.java

@ -0,0 +1,21 @@
1
/*
2
 * Copyright (C) 2013-2014 Zhang Rui <bbcallen@gmail.com>
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package tv.danmaku.ijk.media.player.exceptions;
18
19
public class IjkMediaException extends Exception {
20
    private static final long serialVersionUID = 7234796519009099506L;
21
}

+ 5 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/ffmpeg/FFmpegApi.java

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

+ 62 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/AndroidMediaFormat.java

@ -0,0 +1,62 @@
1
/*
2
 * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package tv.danmaku.ijk.media.player.misc;
18
19
import android.annotation.TargetApi;
20
import android.media.MediaFormat;
21
import android.os.Build;
22
23
public class AndroidMediaFormat implements IMediaFormat {
24
    private final MediaFormat mMediaFormat;
25
26
    public AndroidMediaFormat(MediaFormat mediaFormat) {
27
        mMediaFormat = mediaFormat;
28
    }
29
30
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
31
    @Override
32
    public int getInteger(String name) {
33
        if (mMediaFormat == null)
34
            return 0;
35
36
        return mMediaFormat.getInteger(name);
37
    }
38
39
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
40
    @Override
41
    public String getString(String name) {
42
        if (mMediaFormat == null)
43
            return null;
44
45
        return mMediaFormat.getString(name);
46
    }
47
48
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
49
    @Override
50
    public String toString() {
51
        StringBuilder out = new StringBuilder(128);
52
        out.append(getClass().getName());
53
        out.append('{');
54
        if (mMediaFormat != null) {
55
            out.append(mMediaFormat.toString());
56
        } else {
57
            out.append("null");
58
        }
59
        out.append('}');
60
        return out.toString();
61
    }
62
}

+ 108 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/AndroidTrackInfo.java

@ -0,0 +1,108 @@
1
/*
2
 * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package tv.danmaku.ijk.media.player.misc;
18
19
import android.annotation.TargetApi;
20
import android.media.MediaFormat;
21
import android.media.MediaPlayer;
22
import android.os.Build;
23
24
public class AndroidTrackInfo implements ITrackInfo {
25
    private final MediaPlayer.TrackInfo mTrackInfo;
26
27
    public static AndroidTrackInfo[] fromMediaPlayer(MediaPlayer mp) {
28
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
29
            return fromTrackInfo(mp.getTrackInfo());
30
31
        return null;
32
    }
33
34
    private static AndroidTrackInfo[] fromTrackInfo(MediaPlayer.TrackInfo[] trackInfos) {
35
        if (trackInfos == null)
36
            return null;
37
38
        AndroidTrackInfo androidTrackInfo[] = new AndroidTrackInfo[trackInfos.length];
39
        for (int i = 0; i < trackInfos.length; ++i) {
40
            androidTrackInfo[i] = new AndroidTrackInfo(trackInfos[i]);
41
        }
42
43
        return androidTrackInfo;
44
    }
45
46
    private AndroidTrackInfo(MediaPlayer.TrackInfo trackInfo) {
47
        mTrackInfo = trackInfo;
48
    }
49
50
    @TargetApi(Build.VERSION_CODES.KITKAT)
51
    @Override
52
    public IMediaFormat getFormat() {
53
        if (mTrackInfo == null)
54
            return null;
55
56
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
57
            return null;
58
59
        MediaFormat mediaFormat = mTrackInfo.getFormat();
60
        if (mediaFormat == null)
61
            return null;
62
63
        return new AndroidMediaFormat(mediaFormat);
64
    }
65
66
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
67
    @Override
68
    public String getLanguage() {
69
        if (mTrackInfo == null)
70
            return "und";
71
72
        return mTrackInfo.getLanguage();
73
    }
74
75
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
76
    @Override
77
    public int getTrackType() {
78
        if (mTrackInfo == null)
79
            return MEDIA_TRACK_TYPE_UNKNOWN;
80
81
        return mTrackInfo.getTrackType();
82
    }
83
84
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
85
    @Override
86
    public String toString() {
87
        StringBuilder out = new StringBuilder(128);
88
        out.append(getClass().getSimpleName());
89
        out.append('{');
90
        if (mTrackInfo != null) {
91
            out.append(mTrackInfo.toString());
92
        } else {
93
            out.append("null");
94
        }
95
        out.append('}');
96
        return out.toString();
97
    }
98
99
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
100
    @Override
101
    public String getInfoInline() {
102
        if (mTrackInfo != null) {
103
            return mTrackInfo.toString();
104
        } else {
105
            return "null";
106
        }
107
    }
108
}

+ 28 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IMediaDataSource.java

@ -0,0 +1,28 @@
1
/*
2
 * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package tv.danmaku.ijk.media.player.misc;
18
19
import java.io.IOException;
20
21
@SuppressWarnings("RedundantThrows")
22
public interface IMediaDataSource {
23
    int	 readAt(long position, byte[] buffer, int offset, int size) throws IOException;
24
25
    long getSize() throws IOException;
26
27
    void close() throws IOException;
28
}

+ 30 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IMediaFormat.java

@ -0,0 +1,30 @@
1
/*
2
 * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package tv.danmaku.ijk.media.player.misc;
18
19
public interface IMediaFormat {
20
    // Common keys
21
    String KEY_MIME = "mime";
22
23
    // Video Keys
24
    String KEY_WIDTH = "width";
25
    String KEY_HEIGHT = "height";
26
27
    String getString(String name);
28
29
    int getInteger(String name);
30
}

+ 34 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/ITrackInfo.java

@ -0,0 +1,34 @@
1
/*
2
 * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package tv.danmaku.ijk.media.player.misc;
18
19
public interface ITrackInfo {
20
    int MEDIA_TRACK_TYPE_AUDIO = 2;
21
    int MEDIA_TRACK_TYPE_METADATA = 5;
22
    int MEDIA_TRACK_TYPE_SUBTITLE = 4;
23
    int MEDIA_TRACK_TYPE_TIMEDTEXT = 3;
24
    int MEDIA_TRACK_TYPE_UNKNOWN = 0;
25
    int MEDIA_TRACK_TYPE_VIDEO = 1;
26
27
    IMediaFormat getFormat();
28
29
    String getLanguage();
30
31
    int getTrackType();
32
33
    String getInfoInline();
34
}

+ 209 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IjkMediaFormat.java

@ -0,0 +1,209 @@
1
/*
2
 * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package tv.danmaku.ijk.media.player.misc;
18
19
import android.annotation.TargetApi;
20
import android.os.Build;
21
import android.text.TextUtils;
22
23
import java.util.HashMap;
24
import java.util.Locale;
25
import java.util.Map;
26
27
import tv.danmaku.ijk.media.player.IjkMediaMeta;
28
29
public class IjkMediaFormat implements IMediaFormat {
30
    // Common
31
    public static final String KEY_IJK_CODEC_LONG_NAME_UI = "ijk-codec-long-name-ui";
32
    public static final String KEY_IJK_BIT_RATE_UI = "ijk-bit-rate-ui";
33
34
    // Video
35
    public static final String KEY_IJK_CODEC_PROFILE_LEVEL_UI = "ijk-profile-level-ui";
36
    public static final String KEY_IJK_CODEC_PIXEL_FORMAT_UI = "ijk-pixel-format-ui";
37
    public static final String KEY_IJK_RESOLUTION_UI = "ijk-resolution-ui";
38
    public static final String KEY_IJK_FRAME_RATE_UI = "ijk-frame-rate-ui";
39
40
    // Audio
41
    public static final String KEY_IJK_SAMPLE_RATE_UI = "ijk-sample-rate-ui";
42
    public static final String KEY_IJK_CHANNEL_UI = "ijk-channel-ui";
43
44
    // Codec
45
    public static final String CODEC_NAME_H264 = "h264";
46
47
    public final IjkMediaMeta.IjkStreamMeta mMediaFormat;
48
49
    public IjkMediaFormat(IjkMediaMeta.IjkStreamMeta streamMeta) {
50
        mMediaFormat = streamMeta;
51
    }
52
53
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
54
    @Override
55
    public int getInteger(String name) {
56
        if (mMediaFormat == null)
57
            return 0;
58
59
        return mMediaFormat.getInt(name);
60
    }
61
62
    @Override
63
    public String getString(String name) {
64
        if (mMediaFormat == null)
65
            return null;
66
67
        if (sFormatterMap.containsKey(name)) {
68
            Formatter formatter = sFormatterMap.get(name);
69
            return formatter.format(this);
70
        }
71
72
        return mMediaFormat.getString(name);
73
    }
74
75
    //-------------------------
76
    // Formatter
77
    //-------------------------
78
79
    private static abstract class Formatter {
80
        public String format(IjkMediaFormat mediaFormat) {
81
            String value = doFormat(mediaFormat);
82
            if (TextUtils.isEmpty(value))
83
                return getDefaultString();
84
            return value;
85
        }
86
87
        protected abstract String doFormat(IjkMediaFormat mediaFormat);
88
89
        @SuppressWarnings("SameReturnValue")
90
        protected String getDefaultString() {
91
            return "N/A";
92
        }
93
    }
94
95
    private static final Map<String, Formatter> sFormatterMap = new HashMap<String, Formatter>();
96
97
    {
98
        sFormatterMap.put(KEY_IJK_CODEC_LONG_NAME_UI, new Formatter() {
99
            @Override
100
            public String doFormat(IjkMediaFormat mediaFormat) {
101
                return mMediaFormat.getString(IjkMediaMeta.IJKM_KEY_CODEC_LONG_NAME);
102
            }
103
        });
104
        sFormatterMap.put(KEY_IJK_BIT_RATE_UI, new Formatter() {
105
            @Override
106
            protected String doFormat(IjkMediaFormat mediaFormat) {
107
                int bitRate = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_BITRATE);
108
                if (bitRate <= 0) {
109
                    return null;
110
                } else if (bitRate < 1000) {
111
                    return String.format(Locale.US, "%d bit/s", bitRate);
112
                } else {
113
                    return String.format(Locale.US, "%d kb/s", bitRate / 1000);
114
                }
115
            }
116
        });
117
        sFormatterMap.put(KEY_IJK_CODEC_PROFILE_LEVEL_UI, new Formatter() {
118
            @Override
119
            protected String doFormat(IjkMediaFormat mediaFormat) {
120
                String profile = mediaFormat.getString(IjkMediaMeta.IJKM_KEY_CODEC_PROFILE);
121
                if (TextUtils.isEmpty(profile))
122
                    return null;
123
124
                StringBuilder sb = new StringBuilder();
125
                sb.append(profile);
126
127
                String codecName = mediaFormat.getString(IjkMediaMeta.IJKM_KEY_CODEC_NAME);
128
                if (!TextUtils.isEmpty(codecName) && codecName.equalsIgnoreCase(CODEC_NAME_H264)) {
129
                    int level = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_CODEC_LEVEL);
130
                    if (level < 10)
131
                        return sb.toString();
132
133
                    sb.append(" Profile Level ");
134
                    sb.append((level / 10) % 10);
135
                    if ((level % 10) != 0) {
136
                        sb.append(".");
137
                        sb.append(level % 10);
138
                    }
139
                }
140
141
                return sb.toString();
142
            }
143
        });
144
        sFormatterMap.put(KEY_IJK_CODEC_PIXEL_FORMAT_UI, new Formatter() {
145
            @Override
146
            protected String doFormat(IjkMediaFormat mediaFormat) {
147
                return mediaFormat.getString(IjkMediaMeta.IJKM_KEY_CODEC_PIXEL_FORMAT);
148
            }
149
        });
150
        sFormatterMap.put(KEY_IJK_RESOLUTION_UI, new Formatter() {
151
            @Override
152
            protected String doFormat(IjkMediaFormat mediaFormat) {
153
                int width = mediaFormat.getInteger(KEY_WIDTH);
154
                int height = mediaFormat.getInteger(KEY_HEIGHT);
155
                int sarNum = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_SAR_NUM);
156
                int sarDen = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_SAR_DEN);
157
158
                if (width <= 0 || height <= 0) {
159
                    return null;
160
                } else if (sarNum <= 0 || sarDen <= 0) {
161
                    return String.format(Locale.US, "%d x %d", width, height);
162
                } else {
163
                    return String.format(Locale.US, "%d x %d [SAR %d:%d]", width,
164
                            height, sarNum, sarDen);
165
                }
166
            }
167
        });
168
        sFormatterMap.put(KEY_IJK_FRAME_RATE_UI, new Formatter() {
169
            @Override
170
            protected String doFormat(IjkMediaFormat mediaFormat) {
171
                int fpsNum = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_FPS_NUM);
172
                int fpsDen = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_FPS_DEN);
173
                if (fpsNum <= 0 || fpsDen <= 0) {
174
                    return null;
175
                } else {
176
                    return String.valueOf(((float) (fpsNum)) / fpsDen);
177
                }
178
            }
179
        });
180
        sFormatterMap.put(KEY_IJK_SAMPLE_RATE_UI, new Formatter() {
181
            @Override
182
            protected String doFormat(IjkMediaFormat mediaFormat) {
183
                int sampleRate = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_SAMPLE_RATE);
184
                if (sampleRate <= 0) {
185
                    return null;
186
                } else {
187
                    return String.format(Locale.US, "%d Hz", sampleRate);
188
                }
189
            }
190
        });
191
        sFormatterMap.put(KEY_IJK_CHANNEL_UI, new Formatter() {
192
            @Override
193
            protected String doFormat(IjkMediaFormat mediaFormat) {
194
                int channelLayout = mediaFormat.getInteger(IjkMediaMeta.IJKM_KEY_CHANNEL_LAYOUT);
195
                if (channelLayout <= 0) {
196
                    return null;
197
                } else {
198
                    if (channelLayout == IjkMediaMeta.AV_CH_LAYOUT_MONO) {
199
                        return "mono";
200
                    } else if (channelLayout == IjkMediaMeta.AV_CH_LAYOUT_STEREO) {
201
                        return "stereo";
202
                    } else {
203
                        return String.format(Locale.US, "%x", channelLayout);
204
                    }
205
                }
206
            }
207
        });
208
    }
209
}

+ 96 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/misc/IjkTrackInfo.java

@ -0,0 +1,96 @@
1
/*
2
 * Copyright (C) 2015 Zhang Rui <bbcallen@gmail.com>
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package tv.danmaku.ijk.media.player.misc;
18
19
import android.text.TextUtils;
20
21
import tv.danmaku.ijk.media.player.IjkMediaMeta;
22
23
public class IjkTrackInfo implements ITrackInfo {
24
    private int mTrackType = MEDIA_TRACK_TYPE_UNKNOWN;
25
    private IjkMediaMeta.IjkStreamMeta mStreamMeta;
26
27
    public IjkTrackInfo(IjkMediaMeta.IjkStreamMeta streamMeta) {
28
        mStreamMeta = streamMeta;
29
    }
30
31
    public void setMediaMeta(IjkMediaMeta.IjkStreamMeta streamMeta) {
32
        mStreamMeta = streamMeta;
33
    }
34
35
    @Override
36
    public IMediaFormat getFormat() {
37
        return new IjkMediaFormat(mStreamMeta);
38
    }
39
40
    @Override
41
    public String getLanguage() {
42
        if (mStreamMeta == null || TextUtils.isEmpty(mStreamMeta.mLanguage))
43
            return "und";
44
45
        return mStreamMeta.mLanguage;
46
    }
47
48
    @Override
49
    public int getTrackType() {
50
        return mTrackType;
51
    }
52
53
    public void setTrackType(int trackType) {
54
        mTrackType = trackType;
55
    }
56
57
    @Override
58
    public String toString() {
59
        return getClass().getSimpleName() + '{' + getInfoInline() + "}";
60
    }
61
62
    @Override
63
    public String getInfoInline() {
64
        StringBuilder out = new StringBuilder(128);
65
        switch (mTrackType) {
66
            case MEDIA_TRACK_TYPE_VIDEO:
67
                out.append("VIDEO");
68
                out.append(", ");
69
                out.append(mStreamMeta.getCodecShortNameInline());
70
                out.append(", ");
71
                out.append(mStreamMeta.getBitrateInline());
72
                out.append(", ");
73
                out.append(mStreamMeta.getResolutionInline());
74
                break;
75
            case MEDIA_TRACK_TYPE_AUDIO:
76
                out.append("AUDIO");
77
                out.append(", ");
78
                out.append(mStreamMeta.getCodecShortNameInline());
79
                out.append(", ");
80
                out.append(mStreamMeta.getBitrateInline());
81
                out.append(", ");
82
                out.append(mStreamMeta.getSampleRateInline());
83
                break;
84
            case MEDIA_TRACK_TYPE_TIMEDTEXT:
85
                out.append("TIMEDTEXT");
86
                break;
87
            case MEDIA_TRACK_TYPE_SUBTITLE:
88
                out.append("SUBTITLE");
89
                break;
90
            default:
91
                out.append("UNKNOWN");
92
                break;
93
        }
94
        return out.toString();
95
    }
96
}

+ 142 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/pragma/DebugLog.java

@ -0,0 +1,142 @@
1
/*
2
 * Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
package tv.danmaku.ijk.media.player.pragma;
18
19
import java.util.Locale;
20
21
22
import android.util.Log;
23
24
@SuppressWarnings({"SameParameterValue", "WeakerAccess"})
25
public class DebugLog {
26
    public static final boolean ENABLE_ERROR = Pragma.ENABLE_VERBOSE;
27
    public static final boolean ENABLE_INFO = Pragma.ENABLE_VERBOSE;
28
    public static final boolean ENABLE_WARN = Pragma.ENABLE_VERBOSE;
29
    public static final boolean ENABLE_DEBUG = Pragma.ENABLE_VERBOSE;
30
    public static final boolean ENABLE_VERBOSE = Pragma.ENABLE_VERBOSE;
31
32
    public static void e(String tag, String msg) {
33
        if (ENABLE_ERROR) {
34
            Log.e(tag, msg);
35
        }
36
    }
37
38
    public static void e(String tag, String msg, Throwable tr) {
39
        if (ENABLE_ERROR) {
40
            Log.e(tag, msg, tr);
41
        }
42
    }
43
44
    public static void efmt(String tag, String fmt, Object... args) {
45
        if (ENABLE_ERROR) {
46
            String msg = String.format(Locale.US, fmt, args);
47
            Log.e(tag, msg);
48
        }
49
    }
50
51
    public static void i(String tag, String msg) {
52
        if (ENABLE_INFO) {
53
            Log.i(tag, msg);
54
        }
55
    }
56
57
    public static void i(String tag, String msg, Throwable tr) {
58
        if (ENABLE_INFO) {
59
            Log.i(tag, msg, tr);
60
        }
61
    }
62
63
    public static void ifmt(String tag, String fmt, Object... args) {
64
        if (ENABLE_INFO) {
65
            String msg = String.format(Locale.US, fmt, args);
66
            Log.i(tag, msg);
67
        }
68
    }
69
70
    public static void w(String tag, String msg) {
71
        if (ENABLE_WARN) {
72
            Log.w(tag, msg);
73
        }
74
    }
75
76
    public static void w(String tag, String msg, Throwable tr) {
77
        if (ENABLE_WARN) {
78
            Log.w(tag, msg, tr);
79
        }
80
    }
81
82
    public static void wfmt(String tag, String fmt, Object... args) {
83
        if (ENABLE_WARN) {
84
            String msg = String.format(Locale.US, fmt, args);
85
            Log.w(tag, msg);
86
        }
87
    }
88
89
    public static void d(String tag, String msg) {
90
        if (ENABLE_DEBUG) {
91
            Log.d(tag, msg);
92
        }
93
    }
94
95
    public static void d(String tag, String msg, Throwable tr) {
96
        if (ENABLE_DEBUG) {
97
            Log.d(tag, msg, tr);
98
        }
99
    }
100
101
    public static void dfmt(String tag, String fmt, Object... args) {
102
        if (ENABLE_DEBUG) {
103
            String msg = String.format(Locale.US, fmt, args);
104
            Log.d(tag, msg);
105
        }
106
    }
107
108
    public static void v(String tag, String msg) {
109
        if (ENABLE_VERBOSE) {
110
            Log.v(tag, msg);
111
        }
112
    }
113
114
    public static void v(String tag, String msg, Throwable tr) {
115
        if (ENABLE_VERBOSE) {
116
            Log.v(tag, msg, tr);
117
        }
118
    }
119
120
    public static void vfmt(String tag, String fmt, Object... args) {
121
        if (ENABLE_VERBOSE) {
122
            String msg = String.format(Locale.US, fmt, args);
123
            Log.v(tag, msg);
124
        }
125
    }
126
127
    public static void printStackTrace(Throwable e) {
128
        if (ENABLE_WARN) {
129
            e.printStackTrace();
130
        }
131
    }
132
133
    public static void printCause(Throwable e) {
134
        if (ENABLE_WARN) {
135
            Throwable cause = e.getCause();
136
            if (cause != null)
137
                e = cause;
138
139
            printStackTrace(e);
140
        }
141
    }
142
}

+ 23 - 0
ijkplayer-java/src/main/java/tv/danmaku/ijk/media/player/pragma/Pragma.java

@ -0,0 +1,23 @@
1
/*
2
 * Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package tv.danmaku.ijk.media.player.pragma;
17
18
/*-
19
 * configurated by app project
20
 */
21
public class Pragma {
22
    public static final boolean ENABLE_VERBOSE = true;
23
}

+ 15 - 0
ijkplayer-java/src/main/project.properties

@ -0,0 +1,15 @@
1
# This file is automatically generated by Android Tools.
2
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3
#
4
# This file must be checked in Version Control Systems.
5
#
6
# To customize properties used by the Ant build system edit
7
# "ant.properties", and override values to adapt the script to your
8
# project structure.
9
#
10
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12
13
# Project target.
14
target=android-22
15
android.library=true

+ 6 - 0
ijkplayer-java/src/main/res/values/strings.xml

@ -0,0 +1,6 @@
1
<?xml version="1.0" encoding="utf-8"?>
2
<resources>
3
4
    <string name="ijkplayer_dummy"></string>
5
6
</resources>