最近刚好有在安卓上播放网络视频的一个需求,网上搜了一圈之后找到一个小demo,使用之后觉得作者想法不错,但是代码当中有点问题,会有IllegaleState报错。调整了一下,并且加了个支持几种状态变化的interface,在MediaPlayer状态的处理上多做了一些工作,旧的有问题的代码就不放出来了,看看没错的版本吧。可能有看官会觉得做interface来执行这些事件有些多余,视频播放当中很多执行不是立即生效的,有部分操作实际上是类似异步的,因此做这个还是有必要的,保证了MediaPlayer状态不冲突。另外,安卓支持什么格式,这个就支持什么格式,没有额外的解码功能。

import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.ProgressBar;

import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by chenzhidong on 15-3-15.
 */
public class Player implements MediaPlayer.OnBufferingUpdateListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnSeekCompleteListener, SurfaceHolder.Callback {
    private int videoWidth;
    private int videoHeight;
    public MediaPlayer mediaPlayer;
    private SurfaceHolder surfaceHolder;
    private ProgressBar skbProgress;
    private Timer mTimer = new Timer();
    public long pos = 0;
    public int seek = 0;
    private PlayerListener listener;

    public Player(SurfaceView surfaceView, ProgressBar skbProgress, PlayerListener listener) {
        this.listener = listener;
        this.skbProgress = skbProgress;
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(this);
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        mTimer.schedule(mTimerTask, 0, 1000);
    }

    TimerTask mTimerTask = new TimerTask() {
        @Override
        public void run() {
            if (mediaPlayer == null)
            {
                return;
            }
            if (mediaPlayer.isPlaying() && skbProgress.isPressed() == false)
            {

                handleProgress.sendEmptyMessage(0);
            }
        }
    };
    Handler handleProgress = new Handler() {
        public void handleMessage(Message msg) {

            int position = mediaPlayer.getCurrentPosition()/1000;
            int duration = mediaPlayer.getDuration()/1000;

            if (duration > 0)
            {
                pos = skbProgress.getMax() * position / duration;
                skbProgress.setProgress((int)pos);
            }
            if (listener != null)
            {
                listener.onPlayProgressChangeListener(position, duration);
            }
        }

        ;
    };

    public void play() {
        if (mediaPlayer != null && !mediaPlayer.isPlaying())
        {
            mediaPlayer.start();
            if(listener!=null)
                listener.onStartListener(mediaPlayer.getCurrentPosition());
        }
    }

    public void playUrl(String videoUrl) {
        if (mediaPlayer != null)
        {
            try
            {
                mediaPlayer.reset();
                mediaPlayer.setDataSource(videoUrl);
                mediaPlayer.prepareAsync();//prepare之后自动播放
            } catch (IllegalArgumentException e)
            {
                e.printStackTrace();
            } catch (IllegalStateException e)
            {
                e.printStackTrace();
            } catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }

    public void playUrl(String videoUrl, int seek) {
        if (mediaPlayer != null)
        {
            try
            {
                mediaPlayer.reset();
                mediaPlayer.setDataSource(videoUrl);
                mediaPlayer.prepareAsync();
                this.seek = seek*1000;
            } catch (IllegalArgumentException e)
            {
                e.printStackTrace();
            } catch (IllegalStateException e)
            {
                e.printStackTrace();
            } catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }

    public void pause() {
        if (mediaPlayer != null && mediaPlayer.isPlaying())
        {
            mediaPlayer.pause();
            if (listener != null)
            {
                listener.onPauseListener(mediaPlayer.getCurrentPosition()/1000);
            }
        }
    }

    public void stop() {
        if (mediaPlayer != null && mediaPlayer.isPlaying())
        {
            mediaPlayer.stop();
            mediaPlayer.reset();
            mediaPlayer.release();
            mediaPlayer = null;
            if (listener != null)
            {
                listener.onStopListener();
            }
        }
    }

    public void seek(int seekTo){
        if(mediaPlayer!=null)
        {
            if(!mediaPlayer.isPlaying())
                mediaPlayer.start();
            mediaPlayer.seekTo(seekTo*1000);
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
    }

    @Override
    public void surfaceCreated(SurfaceHolder arg0) {
        if (mediaPlayer != null)
        {
            mediaPlayer.reset();
            mediaPlayer.release();
            mediaPlayer = null;
        }
        mediaPlayer = new MediaPlayer();
        mediaPlayer.setDisplay(surfaceHolder);
        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        mediaPlayer.setLooping(false);
        mediaPlayer.setOnBufferingUpdateListener(this);
        mediaPlayer.setOnPreparedListener(this);
        mediaPlayer.setOnCompletionListener(this);
        mediaPlayer.setOnSeekCompleteListener(this);
        if(listener!=null)
        {
            listener.onInited();
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder arg0) {
        if (mediaPlayer != null)
        {
            mediaPlayer.reset();
            mediaPlayer.release();
            mediaPlayer = null;
        }
    }

    @Override
    public void onPrepared(MediaPlayer arg0) {
        videoWidth = mediaPlayer.getVideoWidth();
        videoHeight = mediaPlayer.getVideoHeight();
        if (videoHeight != 0 && videoWidth != 0)
        {
            arg0.start();
            if (seek > 0)
            {
                arg0.seekTo(seek);
            }
            if (listener != null)
            {
                listener.onStartListener(arg0.getCurrentPosition());
            }
        }
    }

    @Override
    public void onCompletion(MediaPlayer arg0) {
        mTimerTask.cancel();
        mTimer.cancel();
        if (mediaPlayer != null)
        {
            mediaPlayer.reset();
            mediaPlayer.release();
            mediaPlayer = null;
            listener.onCompleteListener();
        }
    }

    @Override
    public void onBufferingUpdate(MediaPlayer arg0, int bufferingProgress) {
        skbProgress.setSecondaryProgress(bufferingProgress);
        //int currentProgress = skbProgress.getMax() * mediaPlayer.getCurrentPosition() / mediaPlayer.getDuration();
        //Log.e(currentProgress + "% play", bufferingProgress + "% buffer");
        if (listener != null)
        {
            listener.onLoadProgressChangeListener(bufferingProgress);
        }
    }

    @Override
    public void onSeekComplete(MediaPlayer mediaPlayer) {
        if(mediaPlayer!=null)
        {
            if (listener != null)
            {
                listener.onSeekListener(mediaPlayer.getCurrentPosition());
            }
        }
    }

    public interface PlayerListener {
        abstract public void onPlayProgressChangeListener(int current, int max);

        abstract public void onLoadProgressChangeListener(int percent);

        abstract public void onCompleteListener();

        abstract public void onStartListener(int start);

        abstract public void onPauseListener(int position);

        abstract public void onStopListener();

        abstract public void onSeekListener(int seekto);

        abstract public void onInited();
    }
}

以上是播放的类,调用的过程很简单,将布局中的surfaceview和progressbar以及listener作为参数传给new出来的Player,如下:

SurfaceView view_video=(SurfaceView)findViewById(R.id.activity_play_video);
ProgressBar view_progress=(ProgressBar)findViewById(R.id.activity_play_progress);
Player player=new Player(view_video,view_progress,new Player.PlayerListener() {
    @Override
    public void onPlayProgressChangeListener(int current, int max) {
        Log.v("Pull","playing: "+current+":"+max);
    }

    @Override
    public void onLoadProgressChangeListener(int percent) {
        Log.v("Pull","loading: "+percent+"%");
    }

    @Override
    public void onCompleteListener() {
        Log.v("Pull","finish playing video");
    }

    @Override
    public void onStartListener(int start) {
        Log.v("Pull","started");
    }

    @Override
    public void onPauseListener(int position) {
        Log.v("Pull","paused");
    }

    @Override
    public void onStopListener() {
        Log.v("Pull","stoped");
    }

    @Override
    public void onSeekListener(int seekto) {
        Log.v("Pull","jump to: "+seekto);
    }

    @Override
    public void onInited() {
        //player.playUrl("http://url"); //从头播放
        //player.playUrl("http://url",123); //从123秒处开始播放
    }
});

当然此处的ProgressBar也可以换成SeekBar,这样就支持拖动了,只要在拖动之后调用player的seek函数即可。
That's all.