封装音视频播放器——MediaPlayer

分类: MXPlayer播放器 发布时间:2018-10-07 21:19

MediaPlayer也就是android下的播放器,可以用于视频和音频的播放。使用MediaPlayer可以简化并且轻松实现android下的音视频的播放。在本篇文章中,对MediaPlayer再一次封装,并且实现播放进度对封装。

static MediaPlayer create(Context context, Uri uri):可以通过该方法或者该方法的重载方法,也可以使用new关键字,创建MediaPlayer实例。

setDataSource(@NonNull Context context, @NonNull Uri uri):为播放器设置播放数据源,uri也就是数据源的uri,同样的该方法也有几个重载方法,具体的请参考api。

prepare:以同步的方式装载流媒体文件,准备播放。该方法还有一个异步的,也就是prepareAsync方法,而prepare会阻塞,直到MediaPlayer准备好播放。

start:开始播放。

pause:暂停播放。

stop:停止播放。

reset:重置,将MediaPlayer重置为未初始化状态。调用此方法,必须通过设置再次初始化。

release:释放与此MediaPlayer对象关联的资源。

1、初始化封装类,单例实现

private SingleAudioPlayer() {}private static class SingletonHolder{ private static SingleAudioPlayer instance = new SingleAudioPlayer();}public static SingleAudioPlayer get(){ return SingleAudioPlayer.SingletonHolder.instance;}2、初始化播放器,并准备装载一个流媒体文件

public void addAndPrepare(final Context context, final List<String> fileNames){ this.context = context.getApplicationContext();    if (fileNames != null && fileNames.size() > 0){ new Thread(new Runnable() { @Override            public void run() { for (String fileName : fileNames) { String filePath = ContextUtils.getSdcardPath() + Constant.PATH_SONG_CACHE + fileName + File.separator;                    audioFiles.add(filePath);                } mediaPlayer = new MediaPlayer();                mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);                try { mediaPlayer.setDataSource(context, Uri.parse(audioFiles.get(audioFiles.size()-1)));                    mediaPlayer.prepare();                    state = STATE_PREPARING;                    currentPos = audioFiles.size()-1;                    //通知                    for (OnPlayerEventListener listener : listeners) { listener.onChange(currentPos);                    } } catch (IOException e) { e.printStackTrace();                } handler.post(new Runnable() { @Override                    public void run() { //添加数据完成之后的回调                        if (mSingleAudioOnPrepareListener != null){ mSingleAudioOnPrepareListener.completePrepare();                        } /**                         * 播放完成                         */                        mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override                            public void onCompletion(MediaPlayer mp) { LogUtils.logI("setOnCompletionListener------>onCompletion");                                if (mOnPlayCompletaListener != null){ mOnPlayCompletaListener.completa();                                } } });                    } });            } }).start();    }}

装载数据完成之后通过mSingleAudioOnPrepareListener回调,播放完成之后通过mOnPlayCompletaListener回调。

3、封装prepare

public void prepare(int pos){ if (mediaPlayer != null){ try { mediaPlayer.setDataSource(context, Uri.parse(audioFiles.get(pos)));            mediaPlayer.prepare();            currentPos = pos;            state = STATE_PREPARING;        } catch (IOException e) { e.printStackTrace();        } }}

mxplayer pro!NuppelVideo!版!

调用了addAndPrepare方法之后不需要调用该方法,因为在addAndPrepare方法中已经调用了prepare方法,而封装prepare方法是为了切换播放资源的时候调用。

这里同样封装了一个prepareAsync方法:

public void prepareAsync(int pos){ if (mediaPlayer != null){ try { mediaPlayer.setDataSource(context, Uri.parse(audioFiles.get(pos)));            mediaPlayer.prepareAsync();            currentPos = pos;            state = STATE_PREPARING;        } catch (IOException e) { e.printStackTrace();        } }}

4、封装start方法

public void start(){ if (mediaPlayer != null){ mediaPlayer.start();        state = STATE_PLAYING;        for (OnPlayerEventListener listener : listeners) { listener.onPlayerStart();        } handler.post(mPublishRunnable);    }}调用该方法就会播放资源。

5、封装pause

public void pause(){ if (mediaPlayer != null && mediaPlayer.isPlaying()){ mediaPlayer.pause();        state = STATE_PAUSE;        for (OnPlayerEventListener listener : listeners) { listener.onPlayerPause();        } }}

6、封装stop

public void stop(){ if (mediaPlayer != null){ mediaPlayer.stop();        state = STATE_IDLE;        for (OnPlayerEventListener listener : listeners) { listener.onPlayerPause();        } }}以上的方法封装都是为了方便我们操作播放器,并且该播放器是根据自己的业务需求来封装,同样同学们也可以根据自己的业务需求来封装一个。

除了平时的播放操作,还有一个比较重要的一点就是播放的进度,所以我们需要做一个播放的进度,增加用户体验。

7、播放进度

private Runnable mPublishRunnable = new Runnable() { @Override    public void run() { if (isPlaying()) { for (OnPlayerEventListener listener : listeners) { listener.onPublish(mediaPlayer.getCurrentPosition());            } } handler.postDelayed(this, TIME_UPDATE);    }};

这里通过mediaPlayer的getCurrentPosition方法获取到播放的进度,并且通过OnPlayerEventListener回调。同时开启线程,每300毫秒回调一次,这样子就达到进度条的效果。

封装的整个播放器的代码如下:

public class SingleAudioPlayer { private static final int STATE_IDLE = 0;//初始    private static final int STATE_PREPARING = 1;//pre    private static final int STATE_PLAYING = 2;//playing    private static final int STATE_PAUSE = 3;//pause    private int state = STATE_IDLE;    private final List<OnPlayerEventListener> listeners = new ArrayList<>();    private Context context;    private MediaPlayer mediaPlayer = null;    //播放的文件路径    private List<String> audioFiles = new ArrayList<>();//    private Handler handler = new Handler();    private Handler handler = new Handler(Looper.getMainLooper());    private static final long TIME_UPDATE = 300L;    private SingleAudioOnPrepareListener mSingleAudioOnPrepareListener;    private OnPlayCompletaListener mOnPlayCompletaListener;    private int currentPos = 0;    private SingleAudioPlayer() {} private static class SingletonHolder{ private static SingleAudioPlayer instance = new SingleAudioPlayer();    } public static SingleAudioPlayer get(){ return SingleAudioPlayer.SingletonHolder.instance;    } /**     * 准备播放     * @param context     * @param fileNames     */    public void addAndPrepare(final Context context, final List<String> fileNames){ this.context = context.getApplicationContext();        if (fileNames != null && fileNames.size() > 0){ new Thread(new Runnable() { @Override                public void run() { for (String fileName : fileNames) { String filePath = ContextUtils.getSdcardPath() + Constant.PATH_SONG_CACHE + fileName + File.separator;                        audioFiles.add(filePath);                    } mediaPlayer = new MediaPlayer();                    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);                    try { mediaPlayer.setDataSource(context, Uri.parse(audioFiles.get(audioFiles.size()-1)));                        mediaPlayer.prepare();                        state = STATE_PREPARING;                        currentPos = audioFiles.size()-1;                        //通知                        for (OnPlayerEventListener listener : listeners) { listener.onChange(currentPos);                        } } catch (IOException e) { e.printStackTrace();                    } handler.post(new Runnable() { @Override                        public void run() { //添加数据完成之后的回调                            if (mSingleAudioOnPrepareListener != null){ mSingleAudioOnPrepareListener.completePrepare();                            } /**                             * 播放完成                             */                            mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override                                public void onCompletion(MediaPlayer mp) { LogUtils.logI("setOnCompletionListener------>onCompletion");                                    if (mOnPlayCompletaListener != null){ mOnPlayCompletaListener.completa();                                    } } });                        } });                } }).start();        } } /**     * 准备     */    public void prepare(int pos){ if (mediaPlayer != null){ try { mediaPlayer.setDataSource(context, Uri.parse(audioFiles.get(pos)));                mediaPlayer.prepare();                currentPos = pos;                state = STATE_PREPARING;            } catch (IOException e) { e.printStackTrace();            } } } public void prepareAsync(int pos){ if (mediaPlayer != null){ try { mediaPlayer.setDataSource(context, Uri.parse(audioFiles.get(pos)));                mediaPlayer.prepareAsync();                currentPos = pos;                state = STATE_PREPARING;            } catch (IOException e) { e.printStackTrace();            } } } /**     * 开始播放     */    public void start(){ if (mediaPlayer != null){ mediaPlayer.start();            state = STATE_PLAYING;            for (OnPlayerEventListener listener : listeners) { listener.onPlayerStart();            } handler.post(mPublishRunnable);        } } public void setAbandonAudioFocus(boolean abandonAudioFocus){ if (abandonAudioFocus) {//            audioFocusManager.abandonAudioFocus();        } } /**     * 暂停播放     */    public void pause(){ if (mediaPlayer != null && mediaPlayer.isPlaying()){ mediaPlayer.pause();            state = STATE_PAUSE;            for (OnPlayerEventListener listener : listeners) { listener.onPlayerPause();            } } } /**     * 停止播放     */    public void stop(){ if (mediaPlayer != null){ mediaPlayer.stop();            state = STATE_IDLE;            for (OnPlayerEventListener listener : listeners) { listener.onPlayerPause();            } } } /**     * 重置MediaPlayer对象为刚刚创建的状态     */    public void reset(){ if (mediaPlayer != null){ mediaPlayer.reset();            state = STATE_IDLE;        } } /**     * 设置是否循环播放     * @param flag     */    public void setLooping(boolean flag){ if (mediaPlayer != null){ mediaPlayer.setLooping(flag);        } } /**     * 重置并重新播放     */    public void resetAndPlay(int pos){ pause();        reset();        prepare(pos);        start();        for (OnPlayerEventListener listener : listeners) { listener.onChange(pos);        } } /**     * 页面销毁的时候调用     * 释放MediaPlayer对象相关的资源     */    public void release(){ if (mediaPlayer != null){ mediaPlayer.pause();            mediaPlayer.stop();            mediaPlayer.release();            mediaPlayer = null;            state = STATE_IDLE;        } audioFiles.clear();    } public void setVolume(float a,float b){ // 恢复音量        if (mediaPlayer != null){ mediaPlayer.setVolume(a,b);        } } /**     * 数据添加完成     */    public interface SingleAudioOnPrepareListener{ void completePrepare();    } public void setSingleAudioOnPrepareListener(SingleAudioOnPrepareListener mOnPrepareListener) { this.mSingleAudioOnPrepareListener = mOnPrepareListener;    } /**     * 播放完成     */    public interface OnPlayCompletaListener{ void completa();    } public void setOnPlayCompletaListener(OnPlayCompletaListener l) { this.mOnPlayCompletaListener = l;    } /**     * 是否在播放     * @return     */    public boolean isPlaying() { return state == STATE_PLAYING;    } public int getDuration(){ if (mediaPlayer != null){ return mediaPlayer.getDuration();        }else{ return 0;        } } /**     * 播放进度     */    private Runnable mPublishRunnable = new Runnable() { @Override        public void run() { if (isPlaying()) { for (OnPlayerEventListener listener : listeners) { listener.onPublish(mediaPlayer.getCurrentPosition());                } } handler.postDelayed(this, TIME_UPDATE);        } };    public void addOnPlayEventListener(OnPlayerEventListener listener) { if (!listeners.contains(listener)) { listeners.add(listener);        } } public void removeOnPlayEventListener(OnPlayerEventListener listener) { listeners.remove(listener);    }}使用首先使用的时候进行初始化,然后在播放

SingleAudioPlayer.get().addAndPrepare(getContext(),songNames);        SingleAudioPlayer.get().setSingleAudioOnPrepareListener(new SingleAudioPlayer.SingleAudioOnPrepareListener() { @Override            public void completePrepare() {//                SingleAudioPlayer.get().start();            } });SingleAudioPlayer.get().start();

在activity的回调方法需要做响应的处理

如果需要的话,还需在onCreate方法中通过SingleAudioPlayer.get().addOnPlayEventListener(mOnPlayerEventListener);设置播放器的监听器,监听器如下:

@Overridepublic void onPause() { super.onPause();    SingleAudioPlayer.get().pause();    LogUtils.logI("SongList_onPause");}@Overridepublic void onStop() { super.onStop();    LogUtils.logI("SongList_onStop");}@Overridepublic void onDestroy() { super.onDestroy();    SingleAudioPlayer.get().release();    SingleAudioPlayer.get().removeOnPlayEventListener(mOnPlayerEventListener);}

以上播放器对于播放wav格式和pcm格式的音频是无效的,不能够播放的,所以播放wav格式和pcm格式的音频需要通过AudioTrack播放,如下方法所示:

public void playDecodeAudio(String record_decode) { int sampleRateInHz = 44100;    int channelConfig = AudioFormat.CHANNEL_OUT_STEREO;    int audioFormat = AudioFormat.ENCODING_PCM_16BIT;    int bufferSizeInBytes = AudioTrack.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);    AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes, AudioTrack.MODE_STREAM);    audioTrack.play();    FileInputStream audioInput = null;    try { audioInput = new FileInputStream(record_decode);        audioInput.read(new byte[44]);        byte[] audioData = new byte[512];        while (audioInput.read(audioData) != -1) { audioTrack.write(audioData, 0, audioData.length);        } } catch (FileNotFoundException e) { e.printStackTrace();    } catch (IOException e) { e.printStackTrace();    } finally { audioTrack.stop();        audioTrack.release();        if (audioInput != null) try { audioInput.close();            } catch (IOException e) { e.printStackTrace();            } }}

这种播放需要设置对一个的音频采样率(sampleRateInHz)、声道(channelConfig)和设置音频数据块,也就是音频数据的比特率(audioFormat)

sampleRateInHz:大多数都是采取44100

audioFormat:分为单声道(CHANNEL_OUT_MONO)和双声道(CHANNEL_OUT_STEREO)

audioFormat:这里采取了16位的,一般都是16位,也有采取8位的。

以上就是可以播放wav格式和pcm格式的音频。

希望该篇文章能够帮助到在MediaPlayer探索中的同学们。