1. Concepts and extensions
VideoView is a media playback display and Control control provided by the android system. Its structure is as follows:
Prototype: VideoView extends SurfaceView implements MediaController. MediaPlayerControl
Class Structure:
Java. lang. Object
Using android. view. View
Using android. view. SurfaceView
Using android. widget. VideoView
Based on the VideoView prototype, we can see that if you build a more complex and distinctive Video View, you must inherit SurfaceView and implement the MediaPlayerControl interface. SurfaceView supports display and MediaPlayerControl supports media control.
2. Case studies
1) VideoView case
(We have not managed the various statuses of MediaPalyer. These statuses make VideoView encapsulation. In addition, when VideoView is created, the MediaPalyer object will be created. When the VideoView object is destroyed, the MediaPlayer object will be released .)
Layout File
<? Xml version = "1.0" encoding = "UTF-8"?>
<LinearLayout xmlns: android = "http://schemas.android.com/apk/res/android" android: orientation = "vertical" android: layout_width = "fill_parent"
Android: layout_height = "fill_parent">
<VideoView android: id = "@ + id/video_view" android: layout_width = "match_parent" android: layout_height = "match_parent"
Android: layout_centerInParent = "true"/>
</LinearLayout>
Main Program:
Public class VideoPlayer extends Activity implements MediaPlayer. OnErrorListener, MediaPlayer. OnCompletionListener {
Public static final String TAG = "VideoPlayer ";
Private VideoView mVideoView;
Private Uri mUri;
Private int mPositionWhenPaused =-1;
Private MediaController mMediaController;
@ Override
Public void onCreate (Bundle savedInstanceState ){
Super. onCreate (savedInstanceState );
SetContentView (R. layout. main );
// Set the screen to landscape.
This. setRequestedOrientation (ActivityInfo. SCREEN_ORIENTATION_LANDSCAPE );
MVideoView = (VideoView) findViewById (R. id. video_view );
// Video file
MUri = Uri. parse (Environment. getExternalStorageDirectory () + "/1.3gp ");
// Create media controller, which allows you to control video playback, pause, reply, and seek operations.
MMediaController = new MediaController (this );
MVideoView. setMediaController (mMediaController );
}
Public void onStart (){
// Play Video
MVideoView. setVideoURI (mUri );
MVideoView. start ();
Super. onStart ();
}
Public void onPause (){
// Stop video when the activity is pause.
MPositionWhenPaused = mVideoView. getCurrentPosition ();
MVideoView. stopPlayback ();
Super. onPause ();
}
Public void onResume (){
// Resume video player
If (mPositionWhenPaused> = 0 ){
MVideoView. seekTo (mPositionWhenPaused );
MPositionWhenPaused =-1;
}
Super. onResume ();
}
Public boolean onError (MediaPlayer player, int arg1, int arg2 ){
Return false;
}
Public void onCompletion (MediaPlayer mp ){
This. finish ();
}
}
2) custom VideoView
Similar to VideoView implementation, SurfaceView is inherited and MediaPlayerControl is implemented.
Public class CustomerVideoView extends SurfaceView implements
MediaPlayerControl {
Private static String TAG = "customer. videoplayer ";
Private boolean pause;
Private boolean seekBackward;
Private boolean seekForward;
Private Uri videoUri;
Private MediaPlayer mediaPlayer;
Private Context context;
Private OnPreparedListener onPreparedListener;
Private int videoWidth;
Private int videoHeight;
Private MediaController mediaController;
Protected SurfaceHolder surfaceHolder;
Private Callback surfaceHolderCallback = new SurfaceHolder. Callback (){
Public void surfaceChanged (SurfaceHolder holder, int format, int w,
Int h ){
}
Public void surfaceCreated (SurfaceHolder holder ){
SurfaceHolder = holder;
If (mediaPlayer! = Null ){
MediaPlayer. setDisplay (surfaceHolder );
Resume ();
} Else {
OpenVideo ();
}
}
Public void surfaceDestroyed (SurfaceHolder holder ){
SurfaceHolder = null;
If (mediaController! = Null ){
MediaController. hide ();
}
Release (true );
}
};
Private void release (boolean cleartargetstate ){
If (mediaPlayer! = Null ){
MediaPlayer. reset ();
MediaPlayer. release ();
MediaPlayer = null;
}
}
Public void resume (){
If (surfaceHolder = null ){
Return;
}
If (mediaPlayer! = Null ){
Return;
}
OpenVideo ();
}
Public CustomerVideoView (Context context, AttributeSet attrs, int defStyle ){
Super (context, attrs, defStyle );
This. context = context;
This. initVideoView ();
}
Public CustomerVideoView (Context context, AttributeSet attrs ){
Super (context, attrs );
This. context = context;
This. initVideoView ();
}
Public CustomerVideoView (Context context ){
Super (context );
This. context = context;
This. initVideoView ();
}
@ Override
Public boolean canPause (){
Return this. pause;
}
@ Override
Public boolean canSeekBackward (){
Return this. seekBackward;
}
@ Override
Public boolean canSeekForward (){
Return this. seekForward;
}
@ Override
Public int getBufferPercentage (){
Return 0;
}
@ Override
Public int getCurrentPosition (){
Return mediaPlayer! = Null? MediaPlayer. getCurrentPosition (): 0;
}
@ Override
Public int getDuration (){
Return mediaPlayer! = Null? MediaPlayer. getDuration (): 0;
}
@ Override
Public boolean isPlaying (){
Return false;
}
@ Override
Public void pause (){
}
@ Override
Public void seekTo (int mSec ){
}
@ Override
Public void start (){
}
Public void setVideoURI (Uri uri ){
This. videoUri = uri;
OpenVideo ();
RequestLayout ();
Invalidate ();
}
Private void openVideo (){
This. mediaPlayer = new MediaPlayer ();
Try {
This. mediaPlayer. setDataSource (this. context, this. videoUri );
} Catch (Exception e ){
Log. e (TAG, e. getMessage ());
Throw new RuntimeException (e );
}
This. mediaPlayer. prepareAsync ();
This. mediaPlayer. setAudioStreamType (AudioManager. STREAM_MUSIC );
This. mediaPlayer. setOnPreparedListener (onPreparedListener );
AttachMediaController ();
}
Private void attachMediaController (){
If (mediaPlayer! = Null & mediaController! = Null ){
MediaController. setMediaPlayer (this );
View anchorView = this. getParent () instanceof View? (View) this
. GetParent (): this;
MediaController. setAnchorView (anchorView );
MediaController. setEnabled (true );
}
}
Public void setMediaController (MediaController controller ){
If (mediaController! = Null ){
MediaController. hide ();
}
MediaController = controller;
AttachMediaController ();
}
Public void setOnPreparedListener (OnPreparedListener onPreparedListener ){
This. onPreparedListener = onPreparedListener;
}
@ Override
Protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec ){
Int width = getDefaultSize (videoWidth, widthMeasureSpec );
Int height = getDefaultSize (videoHeight, heightMeasureSpec );
If (videoWidth> 0 & videoHeight> 0 ){
If (videoWidth * height> width * videoHeight ){
Height = width * videoHeight/videoWidth;
} Else if (videoWidth * height <width * videoHeight ){
Width = height * videoWidth/videoHeight;
}
}
Log. I (TAG, "setting size:" + width + 'X' + height );
SetMeasuredDimension (width, height );
}
Private void initVideoView (){
VideoWidth = 0;
VideoHeight = 0;
GetHolder (). addCallback (surfaceHolderCallback );
GetHolder (). setType (SurfaceHolder. SURFACE_TYPE_PUSH_BUFFERS );
SetFocusable (true );
SetFocusableInTouchMode (true );
RequestFocus ();
}
}
Generally, the rendering and updating of the android interface must be performed by the main ui thread through the Handler mechanism. However, to play a video, you must first change and draw the page in real time. Android provides a mechanism to draw the UI using a separate thread, that is, SurfaceView. To use SurfaceView, you must implement the SurfaceHolder. Callback interface:
SurfaceCreated: After the Surface (SurfaceView contains a Surface instance) is created, this method is called immediately. You can initialize the interface in this method;
SurfaceChanged: when the Surface status changes, such as the size, this method is called. This method is called at least once in the surfaceCreated method;
SurfaceDestroyed, called when the Surface is destroyed.
You cannot directly operate a Surface instance. You must use SurfaceHandler to obtain the SurfaceHandler instance through the getHandler method in SurfaceView.
SurfaceHander has some types used to identify the data source on the Surface instance interface. You can use setType to perform the following operations:
SURFACE_TYPE_NORMAL: Native data cached by RAM
SURFACE_TYPE_HARDWARE: the data obtained through DMA and direct memory access is the data obtained through direct Screen Writing Technology, or data accelerated by other hardware.
SURFACE_TYPE_GPU: GPU-Accelerated Data
SURFACE_TYPE_PUSH_BUFFERS: identifies data from other objects, such as cameras, such as video playback servers (servers with video playback in android, all playing videos are equivalent to clients)
The constructor of CustomerVideoView, which uses the constructor of the superclass. The initVideoView () method is executed to initialize the interface and parameters. Another major content is the openVideo () method:
MediaPlayer. prepareAsync () is used to prepare for playing asynchronously. In addition, there is a prepare () method, which is synchronous, that is, it can only be played after all the downloads are completed. Obviously, the former must be used to play online videos;
The attachMediaController () method is used to append the control bar to the SurfaceView of the video to be played. This method is not completely implemented and therefore cannot be used. You only need to set the MediaPlayerControl instance through the setMediaPlayer method, the OnPreparedListener is used to get the callback for successful loading, and the video length and current time length can be obtained by calling the outside code.