HTML5VideoView.java revision 661e8b1f21f03ea429ff34f8fdb58b68a5049092
1
2package android.webkit;
3
4import android.graphics.SurfaceTexture;
5import android.media.MediaPlayer;
6import android.util.Log;
7import android.webkit.HTML5VideoViewProxy;
8import android.widget.MediaController;
9import android.opengl.GLES20;
10import java.io.IOException;
11import java.util.Map;
12
13/**
14 * @hide This is only used by the browser
15 */
16public class HTML5VideoView implements MediaPlayer.OnPreparedListener{
17    // Due to the fact that SurfaceTexture consume a lot of memory, we make it
18    // as static. m_textureNames is the texture bound with this SurfaceTexture.
19    private static SurfaceTexture mSurfaceTexture = null;
20    private static int[] mTextureNames;
21
22    // Only when the video is prepared, we render using SurfaceTexture.
23    // This in fact is used to avoid showing the obsolete content when
24    // switching videos.
25    private static boolean mReadyToUseSurfTex = false;
26
27    // For handling the seekTo before prepared, we need to know whether or not
28    // the video is prepared. Therefore, we differentiate the state between
29    // prepared and not prepared.
30    // When the video is not prepared, we will have to save the seekTo time,
31    // and use it when prepared to play.
32    private static final int STATE_NOTPREPARED        = 0;
33    private static final int STATE_PREPARED           = 1;
34
35    // We only need state for handling seekTo
36    private int mCurrentState;
37
38    // Basically for calling back the OnPrepared in the proxy
39    private HTML5VideoViewProxy mProxy;
40
41    // Save the seek time when not prepared. This can happen when switching
42    // video besides initial load.
43    private int mSaveSeekTime;
44
45    // This is used to find the VideoLayer on the native side.
46    private int mVideoLayerId;
47
48    // Every video will have one MediaPlayer. Given the fact we only have one
49    // SurfaceTexture, there is only one MediaPlayer in action. Every time we
50    // switch videos, a new instance of MediaPlayer will be created in reset().
51    private MediaPlayer mPlayer;
52
53    private static HTML5VideoView mInstance = new HTML5VideoView();
54
55    // Video control FUNCTIONS:
56    public void start() {
57        if (mCurrentState == STATE_PREPARED) {
58            mPlayer.start();
59            mReadyToUseSurfTex = true;
60        }
61    }
62
63    public void pause() {
64        mPlayer.pause();
65    }
66
67    public int getDuration() {
68        return mPlayer.getDuration();
69    }
70
71    public int getCurrentPosition() {
72        return mPlayer.getCurrentPosition();
73    }
74
75    public void seekTo(int pos) {
76        if (mCurrentState == STATE_PREPARED)
77            mPlayer.seekTo(pos);
78        else
79            mSaveSeekTime = pos;
80    }
81
82    public boolean isPlaying() {
83        return mPlayer.isPlaying();
84    }
85
86    public void release() {
87        mPlayer.release();
88    }
89
90    public void stopPlayback() {
91        mPlayer.stop();
92    }
93
94    private void reset(int videoLayerId) {
95        mPlayer = new MediaPlayer();
96        mCurrentState = STATE_NOTPREPARED;
97        mProxy = null;
98        mVideoLayerId = videoLayerId;
99        mReadyToUseSurfTex = false;
100    }
101
102    public static HTML5VideoView getInstance(int videoLayerId) {
103        // Every time we switch between the videos, a new MediaPlayer will be
104        // created. Make sure we call the m_player.release() when it is done.
105        mInstance.reset(videoLayerId);
106        return mInstance;
107    }
108
109    private HTML5VideoView() {
110        // This is a singleton across WebViews (i.e. Tabs).
111        // HTML5VideoViewProxy will reset the internal state every time a new
112        // video start.
113    }
114
115    public void setMediaController(MediaController m) {
116        this.setMediaController(m);
117    }
118
119    public void setVideoURI(String uri, Map<String, String> headers) {
120        // When switching players, surface texture will be reused.
121        mPlayer.setTexture(getSurfaceTextureInstance());
122
123        // When there is exception, we could just bail out silently.
124        // No Video will be played though. Write the stack for debug
125        try {
126            mPlayer.setDataSource(uri, headers);
127            mPlayer.prepareAsync();
128        } catch (IllegalArgumentException e) {
129            e.printStackTrace();
130        } catch (IllegalStateException e) {
131            e.printStackTrace();
132        } catch (IOException e) {
133            e.printStackTrace();
134        }
135    }
136
137    // TODO [FULL SCREEN SUPPORT]
138
139    // Listeners setup FUNCTIONS:
140    public void setOnCompletionListener(HTML5VideoViewProxy proxy) {
141        mPlayer.setOnCompletionListener(proxy);
142    }
143
144    public void setOnErrorListener(HTML5VideoViewProxy proxy) {
145        mPlayer.setOnErrorListener(proxy);
146    }
147
148    public void setOnPreparedListener(HTML5VideoViewProxy proxy) {
149        mProxy = proxy;
150        mPlayer.setOnPreparedListener(this);
151    }
152
153    // Inline Video specific FUNCTIONS:
154
155    public SurfaceTexture getSurfaceTexture() {
156        return mSurfaceTexture;
157    }
158
159    public void deleteSurfaceTexture() {
160        mSurfaceTexture = null;
161        return;
162    }
163
164    // SurfaceTexture is a singleton here , too
165    private SurfaceTexture getSurfaceTextureInstance() {
166        // Create the surface texture.
167        if (mSurfaceTexture == null)
168        {
169            mTextureNames = new int[1];
170            GLES20.glGenTextures(1, mTextureNames, 0);
171            mSurfaceTexture = new SurfaceTexture(mTextureNames[0]);
172        }
173        return mSurfaceTexture;
174    }
175
176    public int getTextureName() {
177        return mTextureNames[0];
178    }
179
180    public int getVideoLayerId() {
181        return mVideoLayerId;
182    }
183
184    public boolean getReadyToUseSurfTex() {
185        return mReadyToUseSurfTex;
186    }
187
188    public void setFrameAvailableListener(SurfaceTexture.OnFrameAvailableListener l) {
189        mSurfaceTexture.setOnFrameAvailableListener(l);
190    }
191
192    @Override
193    public void onPrepared(MediaPlayer mp) {
194        mCurrentState = STATE_PREPARED;
195        seekTo(mSaveSeekTime);
196        if (mProxy != null)
197            mProxy.onPrepared(mp);
198    }
199
200    // Pause the play and update the play/pause button
201    public void pauseAndDispatch(HTML5VideoViewProxy proxy) {
202        if (isPlaying()) {
203            pause();
204            if (proxy != null) {
205                proxy.dispatchOnPaused();
206            }
207        }
208        mReadyToUseSurfTex = false;
209    }
210
211}
212