Android 視頻播放器 (二):使用MediaPlayer播放視頻


在 Android 視頻播放器 (一):使用VideoView播放視頻 我們講了一下如何使用VideoView播放視頻,了解了基本的播放器的一些知識和內容。也知道VideoView內部封裝的就是MediaPlayer,本文就介紹如何使用MediaPlayer播放視頻。

一、簡介

MediaPlayer是Android中的一個多媒體播放類,其提供的API能滿足簡單的大部分音視頻的播放需求。

下面簡單介紹一下MediaPlayer:

  • MediaPlayer是使用Surface進行視頻的展示的。
  • MediaPlayer只支持mp4、avi、3gp格式的視頻,支持格式相對單一。
  • MediaPlayer可以播放網絡視頻,支持的網絡視頻的協議為:Http協議和RTSP協議兩種。

二、MediaPlayer 使用方法

MediaPlayer 的提供的方法如下:

  • 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):當裝載流媒體完畢的時候回調。

Android通過MediaPlayer控制播放器的狀態的方式來控制媒體文件的播放,其中: 

  • prepare()和prepareAsync() 提供了同步和異步兩種方式設置播放器進入prepare狀態,需要注意的是,如果MediaPlayer實例是由create方法創建的,那么第一次啟動播放前不需要再調用prepare()了,因為create方法里已經調用過了。
  • start()是真正啟動文件播放的方法, 
  • pause()和stop()比較簡單,起到暫停和停止播放的作用, 
  • seekTo()是定位方法,可以讓播放器從指定的位置開始播放,需要注意的是該方法是個異步方法,也就是說該方法返回時並不意味着定位完成,尤其是播放的網絡文件,真正定位完成時會觸發OnSeekComplete.onSeekComplete(),如果需要是可以調用setOnSeekCompleteListener(OnSeekCompleteListener)設置監聽器來處理的。 
  • release()可以釋放播放器占用的資源,一旦確定不再使用播放器時應當盡早調用它釋放資源。 
  • reset()可以使播放器從Error狀態中恢復過來,重新會到Idle狀態。

使用MediaPlayer播放視頻的步驟如下:

  1. 創建MediaPlayer對象,並讓它加載指定的視頻文件;
  2. 在界面布局文件中定義SurfaceView控件,或在程序中創建SurfaceView控件,並為SurfaceView的SurfaceHolder添加Callback監聽器;
  3. 調用MediaPlayer對象的setDisney(SurfaceHolder sh)方法將所播放的視頻圖像輸出到指定的SurfaceView控制;
  4. 調用MediaPlayer的start()、stop()、pause()方法來控制視頻播放。
下圖是一個MediaPlayer對象被支持的播放控制操作驅動的聲明周期和狀態。其中,橢圓代表MediaPlayer可能駐留的狀態,弧線表示驅動MediaPlayer在各個狀態之間遷移的播放控制操作。這里有兩種類型的弧線。由單箭頭開始的弧線代表同步方法調用,而以雙箭頭開頭的弧線代表異步方法調用。

 

三、使用MediaPlayer實現視頻播放

下面我們將展示如何使用MediaPlayer播放香港衛視的視頻流:

1. 聲明權限

需要在AndroidManifest.xml添加權限。

<uses-permission android:name="android.permission.INTERNET" />

2. 編寫SurfaceView布局

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <SurfaceView
            android:id="@+id/surface_view"
            android:layout_width="match_parent"
            android:layout_height="195dp" />
    </LinearLayout>
</android.support.constraint.ConstraintLayout>

3. 編寫播放視頻代碼

public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {

    SurfaceView surfaceView;

    SurfaceHolder surfaceHolder;

    MediaPlayer mediaPlayer;

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

        surfaceView = findViewById(R.id.surface_view);

        surfaceHolder = surfaceView.getHolder();

        surfaceHolder.addCallback(this);

        mediaPlayer = new MediaPlayer();

        try {
            mediaPlayer.setDataSource("http://live.hkstv.hk.lxdns.com/live/hks/playlist.m3u8");
        } catch (IOException e) {
            e.printStackTrace();
        }
        mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mp) {
                mp.start();
            }
        });
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        Surface surface = holder.getSurface();
        mediaPlayer.setSurface(surface);
        mediaPlayer.prepareAsync();
    }

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

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

    }
}

四、MediaPlayer使用注意事項

  1. 在使用start()播放流媒體之前,需要裝載流媒體資源。這里最好使用prepareAsync()用異步的方式裝載流媒體資源。因為流媒體資源的裝載是會消耗系統資源的,在一些硬件不理想的設備上,如果使用prepare()同步的方式裝載資源,可能會造成UI界面的卡頓,這是非常影響用於體驗的。因為推薦使用異步裝載的方式,為了避免還沒有裝載完成就調用start()而報錯的問題,需要綁定MediaPlayer.setOnPreparedListener()事件,它將在異步裝載完成之后回調。異步裝載還有一個好處就是避免裝載超時引發ANR((Application Not Responding)錯誤。
    mediaPlayer = new MediaPlayer();
    mediaPlayer.setDataSource(path);
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    // 通過異步的方式裝載媒體資源
    mediaPlayer.prepareAsync();
    mediaPlayer.setOnPreparedListener(new OnPreparedListener() {                    
         @Override
         public void onPrepared(MediaPlayer mp) {
              // 裝載完畢回調
              mediaPlayer.start();
         }
    });
  1. 使用完MediaPlayer需要回收資源。MediaPlayer是很消耗系統資源的,所以在使用完MediaPlayer,不要等待系統自動回收,最好是主動回收資源
    if (mediaPlayer != null && mediaPlayer.isPlaying()) {
          mediaPlayer.stop();
          mediaPlayer.release();
          mediaPlayer = null;
    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM