blob: 2312160f5c66b3433aa0827e59606d03619347ea [file] [log] [blame]
package android.webkit;
import android.graphics.SurfaceTexture;
import android.media.MediaPlayer;
import android.util.Log;
import android.webkit.HTML5VideoViewProxy;
import android.widget.MediaController;
import android.opengl.GLES20;
import java.io.IOException;
import java.util.Map;
/**
* @hide This is only used by the browser
*/
public class HTML5VideoView implements MediaPlayer.OnPreparedListener{
// Due to the fact that SurfaceTexture consume a lot of memory, we make it
// as static. m_textureNames is the texture bound with this SurfaceTexture.
private static SurfaceTexture mSurfaceTexture = null;
private static int[] mTextureNames;
// Only when the video is prepared, we render using SurfaceTexture.
// This in fact is used to avoid showing the obsolete content when
// switching videos.
private static boolean mReadyToUseSurfTex = false;
// For handling the seekTo before prepared, we need to know whether or not
// the video is prepared. Therefore, we differentiate the state between
// prepared and not prepared.
// When the video is not prepared, we will have to save the seekTo time,
// and use it when prepared to play.
private static final int STATE_NOTPREPARED = 0;
private static final int STATE_PREPARED = 1;
// We only need state for handling seekTo
private int mCurrentState;
// Basically for calling back the OnPrepared in the proxy
private HTML5VideoViewProxy mProxy;
// Save the seek time when not prepared. This can happen when switching
// video besides initial load.
private int mSaveSeekTime;
// This is used to find the VideoLayer on the native side.
private int mVideoLayerId;
// Every video will have one MediaPlayer. Given the fact we only have one
// SurfaceTexture, there is only one MediaPlayer in action. Every time we
// switch videos, a new instance of MediaPlayer will be created in reset().
private MediaPlayer mPlayer;
private static HTML5VideoView mInstance = new HTML5VideoView();
// Video control FUNCTIONS:
public void start() {
if (mCurrentState == STATE_PREPARED) {
mPlayer.start();
mReadyToUseSurfTex = true;
}
}
public void pause() {
mPlayer.pause();
}
public int getDuration() {
return mPlayer.getDuration();
}
public int getCurrentPosition() {
return mPlayer.getCurrentPosition();
}
public void seekTo(int pos) {
if (mCurrentState == STATE_PREPARED)
mPlayer.seekTo(pos);
else
mSaveSeekTime = pos;
}
public boolean isPlaying() {
return mPlayer.isPlaying();
}
public void release() {
mPlayer.release();
}
public void stopPlayback() {
mPlayer.stop();
}
private void reset(int videoLayerId) {
mPlayer = new MediaPlayer();
mCurrentState = STATE_NOTPREPARED;
mProxy = null;
mVideoLayerId = videoLayerId;
mReadyToUseSurfTex = false;
}
public static HTML5VideoView getInstance(int videoLayerId) {
// Every time we switch between the videos, a new MediaPlayer will be
// created. Make sure we call the m_player.release() when it is done.
mInstance.reset(videoLayerId);
return mInstance;
}
private HTML5VideoView() {
// This is a singleton across WebViews (i.e. Tabs).
// HTML5VideoViewProxy will reset the internal state every time a new
// video start.
}
public void setMediaController(MediaController m) {
this.setMediaController(m);
}
public void setVideoURI(String uri, Map<String, String> headers) {
// When switching players, surface texture will be reused.
mPlayer.setTexture(getSurfaceTextureInstance());
// When there is exception, we could just bail out silently.
// No Video will be played though. Write the stack for debug
try {
mPlayer.setDataSource(uri, headers);
mPlayer.prepareAsync();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// TODO [FULL SCREEN SUPPORT]
// Listeners setup FUNCTIONS:
public void setOnCompletionListener(HTML5VideoViewProxy proxy) {
mPlayer.setOnCompletionListener(proxy);
}
public void setOnErrorListener(HTML5VideoViewProxy proxy) {
mPlayer.setOnErrorListener(proxy);
}
public void setOnPreparedListener(HTML5VideoViewProxy proxy) {
mProxy = proxy;
mPlayer.setOnPreparedListener(this);
}
// Inline Video specific FUNCTIONS:
public SurfaceTexture getSurfaceTexture() {
return mSurfaceTexture;
}
public void deleteSurfaceTexture() {
mSurfaceTexture = null;
return;
}
// SurfaceTexture is a singleton here , too
private SurfaceTexture getSurfaceTextureInstance() {
// Create the surface texture.
if (mSurfaceTexture == null)
{
mTextureNames = new int[1];
GLES20.glGenTextures(1, mTextureNames, 0);
mSurfaceTexture = new SurfaceTexture(mTextureNames[0]);
}
return mSurfaceTexture;
}
public int getTextureName() {
return mTextureNames[0];
}
public int getVideoLayerId() {
return mVideoLayerId;
}
public boolean getReadyToUseSurfTex() {
return mReadyToUseSurfTex;
}
public void setFrameAvailableListener(SurfaceTexture.OnFrameAvailableListener l) {
mSurfaceTexture.setOnFrameAvailableListener(l);
}
@Override
public void onPrepared(MediaPlayer mp) {
mCurrentState = STATE_PREPARED;
seekTo(mSaveSeekTime);
if (mProxy != null)
mProxy.onPrepared(mp);
}
// Pause the play and update the play/pause button
public void pauseAndDispatch(HTML5VideoViewProxy proxy) {
if (isPlaying()) {
pause();
if (proxy != null) {
proxy.dispatchOnPaused();
}
}
mReadyToUseSurfTex = false;
}
}