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