Android 使用MediaPlayer播放本地視頻

MediaPlayer可以播放視頻和音頻,並且它支持本地和網絡文件的播放。本篇文章是使用MediaPlayer播放本地視頻,如果覺得使用MediaPlayer比較麻煩,也可以選擇VideoView播放視頻。

MainActivity.java 代碼如下:

package per.juan.playvideodome;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;

public class MainActivity extends AppCompatActivity {
    SurfaceView mSvVideoPlayer;

    private MediaPlayer mMediaPlayer;
    private int mPosition = 0;
    private boolean hasActiveHolder = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mSvVideoPlayer = findViewById(R.id.sv_video_player);
        playVideo();
    }

    /**
     * 播放視頻
     */
    public void playVideo() {
        if (mMediaPlayer == null) {
            //實例化MediaPlayer對象
            mMediaPlayer = new MediaPlayer();
            mSvVideoPlayer.setVisibility(View.VISIBLE);
            boolean mHardwareDecoder = false;
            // 不維持自身緩衝區,直接顯示
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB && mHardwareDecoder) {
                mSvVideoPlayer.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
            }
            mSvVideoPlayer.getHolder().setFixedSize(getScreenWidth(), getScreenHeight());
            mSvVideoPlayer.getHolder().setKeepScreenOn(true);//保持屏幕常亮
            mSvVideoPlayer.getHolder().addCallback(new SurFaceCallback());
        }
    }

    /**
     * 向player中設置dispay,也就是SurfaceHolder。但此時有可能SurfaceView還沒有創建成功,所以需要監聽SurfaceView的創建事件
     */
    private final class SurFaceCallback implements SurfaceHolder.Callback {

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            if (mMediaPlayer == null) {
                return;
            }
            if (!hasActiveHolder) {
                play(mPosition);
                hasActiveHolder = true;
            }
            if (mPosition > 0) {
                play(mPosition);
                mPosition = 0;
            }
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            if (mMediaPlayer == null) {
                return;
            }
            if (mMediaPlayer.isPlaying()) {
                mMediaPlayer.stop();
                mPosition = mMediaPlayer.getCurrentPosition();
            }
        }

        private void play(int position) {
            try {
                //添加播放視頻的路徑與配置MediaPlayer
                AssetFileDescriptor fileDescriptor = getResources().openRawResourceFd(R.raw.info);
                mMediaPlayer.reset();
                //給mMediaPlayer添加預覽的SurfaceHolder,將播放器和SurfaceView關聯起來
                mMediaPlayer.setDisplay(mSvVideoPlayer.getHolder());

                mMediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),
                        fileDescriptor.getStartOffset(),
                        fileDescriptor.getLength());
                // 緩衝
                mMediaPlayer.prepare();
                mMediaPlayer.setOnBufferingUpdateListener(new BufferingUpdateListener());
                mMediaPlayer.setOnPreparedListener(new PreparedListener(position));
                mMediaPlayer.setOnCompletionListener(new CompletionListener());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 緩衝變化時回調
     */
    private final class BufferingUpdateListener implements MediaPlayer.OnBufferingUpdateListener {

        @Override
        public void onBufferingUpdate(MediaPlayer mp, int percent) {
        }
    }

    /**
     * 準備完成回調
     * 只有當播放器準備好了之後才能夠播放,所以播放的出發只能在觸發了prepare之後
     */
    private final class PreparedListener implements MediaPlayer.OnPreparedListener {
        private int position;

        public PreparedListener(int position) {
            this.position = position;
        }

        @Override
        public void onPrepared(MediaPlayer mp) {
            mMediaPlayer.start();
            if (position > 0) {
                mMediaPlayer.seekTo(position);
            }
        }
    }

    /**
     * 播放結束時回調
     */
    private final class CompletionListener implements MediaPlayer.OnCompletionListener {

        @Override
        public void onCompletion(MediaPlayer mp) {
            mMediaPlayer.start();
        }
    }

    @Override
    public void onDestroy() {
        //釋放內存,MediaPlayer底層是運行C++的函數方法,不使用後必需釋放內存
        if (mMediaPlayer != null) {
            if (mMediaPlayer.isPlaying()) {
                mMediaPlayer.pause();
                mPosition = mMediaPlayer.getCurrentPosition();
            }
            mMediaPlayer.release();
            mMediaPlayer = null;
        }
        super.onDestroy();
    }

    private int getScreenWidth() {
        return ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth();
    }

    private int getScreenHeight() {
        return ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
                .getHeight();
    }
}

activity_main.xml文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <SurfaceView
        android:id="@+id/sv_video_player"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone" />

</RelativeLayout>

由於代碼都有寫的註釋,這裏就不一一贅述啦!用到的API主要有:

  • void setDataSource(String path) 通過一個具體的路徑來設置MediaPlayer的數據源,path可以是本地的一個路徑,也可以是一個網絡路徑
  • void setDataSource(Context context, Uri uri) 通過給定的Uri來設置MediaPlayer的數據源,這裏的Uri可以是網絡路徑或是一個ContentProvider的Uri。
  • void setDataSource(MediaDataSource dataSource) 通過提供的MediaDataSource來設置數據源
  • void setDataSource(FileDescriptor fd) 通過文件描述符FileDescriptor來設置數據源
  • int getCurrentPosition() 獲取當前播放的位置
  • int getAudioSessionId() 返回音頻的session ID
  • int getDuration() 得到文件的時間
  • TrackInfo[] getTrackInfo() 返回一個track信息的數組
  • boolean isLooping () 是否循環播放
  • boolean isPlaying() 是否正在播放
  • void pause () 暫停
  • void start () 開始
  • void stop () 停止
  • void prepare() 同步的方式裝載流媒體文件。
  • void prepareAsync() 異步的方式裝載流媒體文件。
  • void reset() 重置MediaPlayer至未初始化狀態。
  • void release () 回收流媒體資源。
  • void seekTo(int msec) 指定播放的位置(以毫秒爲單位的時間)
  • void setAudioStreamType(int streamtype) 指定流媒體類型
  • void setLooping(boolean looping) 設置是否單曲循環
  • void setNextMediaPlayer(MediaPlayer next) 當 當前這個MediaPlayer播放完畢後,MediaPlayer next開始播放
  • void setWakeMode(Context context, int mode):設置CPU喚醒的狀態。
  • setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener) 網絡流媒體的緩衝變化時回調
  • setOnCompletionListener(MediaPlayer.OnCompletionListener listener) 網絡流媒體播放結束時回調
  • setOnErrorListener(MediaPlayer.OnErrorListener listener) 發生錯誤時回調
  • setOnPreparedListener(MediaPlayer.OnPreparedListener listener):當裝載流媒體完畢的時候回調。
  • setOnInfoListener(OnInfoListener l) 信息監聽

好了,本篇文章就這樣了,存在總結不到位的地方還望指導,感謝_
源碼下載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章