Surfaceview
Let's start by explaining how most software resolves a video stream. First it needs to determine the format of the video, which is related to decoding, different formats of video coding is different, not the focus here. Know the video encoding format, and then decoding through the encoding format, and finally get a frame of the image, and these images quickly displayed on the interface, that is, to play a video. Surfaceview is doing this in Android.
Since Surfaceview is used in conjunction with MediaPlayer, MediaPlayer also provides the appropriate method to set the Surfaceview display image, just to specify MediaPlayer for Surfaceview display images. Its full signature is as follows:
void Setdisplay (Surfaceholder sh)
It needs to pass a Surfaceholder object, Surfaceholder can be understood as Surfaceview loading a container for a frame image that needs to be displayed, which can be obtained through the Surfaceholder.getholder () method.
The steps to play a video with MediaPlayer with Surfaceview are roughly consistent with playback using MediaPlayer playback MP3, with the additional settings shown for Surfaceview.
Surfaceview Double buffering
As mentioned above, Surfaceview and most video applications, the video stream is parsed into a frame of the image to display, but if the resolution of the process into a thread to complete, it may be in the previous frame image has been shown, the next frame image has not been able to parse, This can cause the picture to be not smooth or the audio and video out of sync problem. So Surfaceview, like most video applications, uses a double-buffered mechanism to display frame images. So what is double buffering? Double buffering can be understood as two threads take turns to parse the video stream frame image, when a thread parsing the frame image, the image is rendered to the interface, while another thread begins to parse the next frame of the image, so that two threads take turns to parse the video stream, in order to achieve smooth playback effect.
Surfaceholder
The Surfaceview internally implements a double-buffering mechanism, but the implementation of this function consumes system memory very much. Because of the limitations of mobile devices, Android in the design of the time specified, Surfaceview if the user is visible, create Surfaceview Surfaceholder used to display the video stream resolution of the frame picture, if found When the surfaceview becomes invisible to the user, the Surfaceview Surfaceholder is destroyed immediately to achieve the purpose of saving the system resources.
If the developer does not maintain the surfaceholder, there will be a minimized program, and then open the application, the sound of the video continues to play, but does not display the picture, this is because when the surfaceview is not visible to the user, The previous surfaceholder has been destroyed, and once again, the interface Surfaceholder is already a new surfaceholder. So Surfaceholder need our developers to code maintenance, maintenance Surfaceholder need to use a callback, Surfaceholder.callback (), it needs to implement three of the following three methods:
- void surfacedestroyed (Surfaceholder holder): callback when Surfaceholder is destroyed.
- void surfacecreated (Surfaceholder holder): callback when Surfaceholder is created.
- void Surfacechange (Surfaceholder holder): When the size of the surfaceholder is changed, it is recalled.
The following is the process of the invocation of these three methods, in the application of the Surfaceholder implementation of the three methods, first into the application, Surfaceholder was created, after the creation will change the size of Surfaceholder, Then press the home key to fall back to the desktop to destroy the Surfaceholder, then enter the application, re-surfaceholder and change its size.
Demo Example of Surfaceview
It says so much about Surfaceview, the following is a demo of how to play the video Surfaceview, add a scroll bar to show progress, you can also drag the scroll bar to select the playback position, the demo's comments are more complete.
Import Java.io.File; Import Android.media.AudioManager; Import Android.media.MediaPlayer; Import Android.media.MediaPlayer.OnCompletionListener; Import Android.media.MediaPlayer.OnErrorListener; Import Android.media.MediaPlayer.OnPreparedListener; Import Android.os.Bundle; Import android.app.Activity; Import Android.util.Log; Import Android.view.SurfaceHolder; Import Android.view.SurfaceHolder.Callback; Import Android.view.SurfaceView; Import Android.view.View; Import Android.widget.Button; Import Android.widget.EditText; Import Android.widget.SeekBar; Import Android.widget.SeekBar.OnSeekBarChangeListener; Import Android.widget.Toast; public class Mainactivity extends Activity {private final String TAG = "main"; private EditText Et_path; private Surfacev Iew SV; Private Button Btn_play, Btn_pause, Btn_replay, btn_stop; Private MediaPlayer MediaPlayer; Private SeekBar SeekBar; private int currentposition = 0; Private Boolean isplaying; @Override protected void OnCreate (Bundle saveDinstancestate) {super.oncreate (savedinstancestate); Setcontentview (R.layout.activity_main); SeekBar = (SeekBar) Findviewbyid (R.id.seekbar); SV = (Surfaceview) Findviewbyid (R.ID.SV); Et_path = (EditText) Findviewbyid (R.id.et_path); Btn_play = (Button) Findviewbyid (R.id.btn_play); Btn_pause = (Button) Findviewbyid (r.id.btn_pause); Btn_replay = (Button) Findviewbyid (R.id.btn_replay); Btn_stop = (Button) Findviewbyid (r.id.btn_stop); Btn_play.setonclicklistener (click); Btn_pause.setonclicklistener (click); Btn_replay.setonclicklistener (click); Btn_stop.setonclicklistener (click); Add callback Sv.getholder () to Surfaceholder. Addcallback (callback); Properties that need to be set under version 4.0//set SURFACE does not maintain its own buffer, but waits for the screen's rendering engine to push the content to the interface//Sv.getholder (). SetType (Surfaceholder.surface_type_ Push_buffers); Add a progress Change event Seekbar.setonseekbarchangelistener for the progress bar; } private Callback Callback = new Callback () {//Surfaceholder is modified when callback @Override public void surfacedestroyed (Surfaceho Lder holder) {log.i (TAG, "Surfaceholder Be destroyed "); When destroying Surfaceholder, record the current playback position and stop playing if (mediaPlayer! = null && mediaplayer.isplaying ()) {currentposition = media Player.getcurrentposition (); Mediaplayer.stop (); }} @Override public void surfacecreated (Surfaceholder holder) {log.i (TAG, "Surfaceholder is created"); if (CurrentPosition &G T 0) {//When creating Surfaceholder, if there is a position last played, play (CurrentPosition) is played at the last playback position; currentposition = 0;}} @Override public void surfacechanged (surfaceholder holder, int format, int width, int height) {log.i (TAG, "Surfaceholder Size is changed "); } }; Private Onseekbarchangelistener change = new Onseekbarchangelistener () {@Override public void Onstoptrackingtouch (seekb Ar seekBar) {//When the progress bar stops modifying, the tick int progress = seekbar.getprogress () of the current progress bar is triggered//is obtained, if (mediaPlayer! = null && Medi Aplayer.isplaying ()) {//sets the current playing position mediaplayer.seekto (progress);}} @Override public void Onstarttrackingtouch (SeekBar SeekBar) {} @Override public void onprogresschanged (SeekBar seekba R, int progress, Boolean fromuser) {}}; Private View.onclicklistener click = New View.onclicklistener () {@Override public void OnClick (View v) {switch (v.ge TId ()) {case R.id.btn_play:play (0), break, Case r.id.btn_pause:pause (), break, Case R.id.btn_replay:replay (), Break, C ASE R.id.btn_stop:stop (); Break Default:break; } } }; /* * Stop playing */protected void Stop () {if (MediaPlayer! = null && mediaplayer.isplaying ()) {mediaplayer.stop (); med Iaplayer.release (); MediaPlayer = null; Btn_play.setenabled (TRUE); IsPlaying = false; }}/** * start playing * * @param msec Play initial position */protected void play (final int msec) {//Get video file address String path = Et_path.gettext (). toString (). Trim (); File File = new file (path); if (!file.exists ()) {Toast.maketext (this, "Video file path error", 0). Show (); return; try {mediaPlayer = new MediaPlayer (); MEDIAPL Ayer.setaudiostreamtype (Audiomanager.stream_music); Set the playback video source Mediaplayer.setdatasource (File.getabsolutepath ()); Set the Surfaceholder Mediaplayer.setdisplay of the display video (sV.getholder ()); LOG.I (TAG, "Start loading"); Mediaplayer.prepareasync (); Mediaplayer.setonpreparedlistener (New Onpreparedlistener () {@Override public void onprepared (MediaPlayer MP) {LOG.I (T AG, "load-complete"); Mediaplayer.start (); Play Mediaplayer.seekto (msec) in the initial position; Set the maximum progress of the progress bar to the maximum playback duration of the video stream Seekbar.setmax (Mediaplayer.getduration ()); Start thread, update progress bar's scale new thread () {@Override public void run () {try {isplaying = true; isplaying} {int current = MediaPlayer. GetCurrentPosition (); Seekbar.setprogress (current); Sleep (500); }} catch (Exception e) {e.printstacktrace ();}} }.start (); Btn_play.setenabled (FALSE); } }); Mediaplayer.setoncompletionlistener (New Oncompletionlistener () {@Override public void Oncompletion (MediaPlayer MP) {/ /callback Btn_play.setenabled (TRUE) after playback is complete; } }); Mediaplayer.setonerrorlistener (New Onerrorlistener () {@Override public boolean onError (MediaPlayer MP, int "what, int ex TRA) {//Error replay play (0); isplaying = false; return false;}); } catch (Exception e){E.printstacktrace ();} }/** * Restart playback */protected void Replay () {if (MediaPlayer! = null && mediaplayer.isplaying ()) {mediaplayer.se Ekto (0); Toast.maketext (This, "replay", 0). Show (); Btn_pause.settext ("pause"); Return } isplaying = false; Play (0); }/** * Pause or Resume */protected void pause () {if (Btn_pause.gettext (). toString ().. trim (). Equals ("continue")) {Btn_pause.settext ("temporary Stop "); Mediaplayer.start (); Toast.maketext (This, "continue playing", 0). Show (); Return } if (MediaPlayer! = null && mediaplayer.isplaying ()) {mediaplayer.pause (); Btn_pause.settext ("Continue"); Toast.maketext (This, "pause playback", 0). Show (); } } }
android--Video Player