1. 程式人生 > >使用SurfaceView&MediaPlayer播放視訊

使用SurfaceView&MediaPlayer播放視訊

SurfaceView

個人理解:SurfaceView跟普通的如TextView、Button等不一樣,它跟它的檢視容器並不是在同一個檢視層上,它的 UI 顯示也可以不在一個獨立的執行緒中完成,所以對 SurfaceView 的繪製並不會影響到主執行緒的執行。如果需要在另外的執行緒繪製介面或者渲染UI介面需要較長時間則可以選擇使用SurfaceView。
使用SurfaceView常與SurfaceHolder 及surfaceHolder.callback一塊使用 還可以例項化一個Runnable 在run方法中繪製View在繪畫開始需要
Canvas mCanvas = mHolder.lockCanvas(); // 獲得畫布物件 。在繪畫結束 時需要
mHolder.unlockCanvasAndPost(mCanvas); // 完成畫畫,把畫布顯示在螢幕。

private SurfaceHolder mSurfaceHolder;
private SurfaceView mSurfaceView;
mSurfaceView = (SurfaceView) view.findViewById(R.id.surfaceView);
        mSurfaceHolder = mSurfaceView.getHolder();
        mSurfaceHolder.addCallback(new HoldCallback());

private class HoldCallback implements SurfaceHolder
.Callback {
@Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { //當Surface尺寸等引數改變時觸發 } @Override public void surfaceCreated(SurfaceHolder holder) { //此處耗時操作的開始 } @Override public
void surfaceDestroyed(SurfaceHolder holder){ //耗時操作結束釋放資源等 } }

MediaPlayer

MediaPlayer的API
談起MediaPlayer不看安卓關於播放的圖就說不過去
這裡寫圖片描述
MediaPlayer關於播放器所有的操作按照這張圖。能用程式碼解決的不廢話。
說明:

  1. 每一個方法的呼叫必須在MediaPlayer特定的狀態中prepareAsync()在{Idle, Prepared, Started, Paused, PlaybackCompleted, Error}就會出錯;
  2. MediaPlayer在執行播放動作前必須指定載入視訊的SurfaceHolder mMediaPlayer.setDisplay(mSurfaceHolder);否者就會只有聲音而沒有影象,同時也需要設定這個媒體播放器的音訊流型別mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);且這個方法必須在prepareAsync(),或者prepare();方法前。
  3. 可能用到的方法getDuration();//獲取視訊時長、getCurrentPosition();//當前播放的時間seekTo(int msec) //選擇時段播放
  4. 載入字幕mMediaPlayer.addTimedTextSource(path, MediaPlayer.MEDIA_MIMETYPE_TEXT_SUBRIP);
  5. 獲取視訊的縮圖Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(path,
    MediaStore.Video.Thumbnails.MINI_KIND);
  6. 從ContentResolver 中獲取視訊列表傳入合適的URI即可,如:Media.EXTERNAL_CONTENT_URI 、Media.INTERNAL_CONTENT_URI
    public final Cursor query(Uri uri, String[] projection,
    String selection, String[] selectionArgs, String sortOrder) {
    return query(uri, projection, selection, selectionArgs, sortOrder, null);
    }
<?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/surfaceView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <LinearLayout
        android:id="@+id/ll_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="#33000000"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:paddingBottom="10dp"
        android:paddingTop="10dp" >

        <LinearLayout
            android:id="@+id/img_play"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_marginLeft="5dp"
            android:gravity="center"
            android:visibility="gone" >

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:clickable="false"
                android:src="@mipmap/vedio_play" />
        </LinearLayout>

        <LinearLayout
            android:id="@+id/img_pause"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_marginLeft="30dp"
            android:layout_marginStart="30dp"
            android:gravity="center"
            android:visibility="visible" >

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:clickable="false"
                android:src="@mipmap/zanting" />
        </LinearLayout>

        <TextView
            android:id="@+id/tv_current_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="2dp"
            android:layout_marginRight="2dp"
            android:text="00:00"
            android:textColor="#ffffff"
            android:textSize="14sp" />

        <RelativeLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1" >

            <SeekBar
                android:id="@+id/seekbar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true" />
        </RelativeLayout>

        <LinearLayout
            android:id="@+id/iv_resize"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="center_vertical"
            android:gravity="center_vertical"
            android:orientation="horizontal"
            android:paddingRight="5dp" >

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:gravity="bottom"
                android:orientation="horizontal" >

                <TextView
                    android:id="@+id/tv_duration_time"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="2dp"
                    android:layout_marginRight="2dp"
                    android:text="00:00"
                    android:textColor="#acacac"
                    android:textSize="14sp" />
            </LinearLayout>

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="5dp"
                android:layout_marginRight="10dp"
                android:clickable="false"
                android:src="@mipmap/quanp" />
        </LinearLayout>
    </LinearLayout>
</RelativeLayout>

這裡寫圖片描述

package me.itangqi.waveloadingview.view;

import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.widget.SeekBar;
import android.widget.TextView;

import java.io.IOException;

import me.itangqi.waveloadingview.R;

public class MediaPlayerActivity extends AppCompatActivity {
    private String TAG = MediaPlayerActivity.class.getSimpleName();
    private SurfaceHolder mSurfaceHolder;
    private SurfaceView mSurfaceView;
    private MediaPlayer mMediaPlayer;
    private SeekBar mSeekBar;
    private static final  int MESSAGE_UPDATE_TIME = 0x01;
    private TextView mDurationTime ;
    private TextView mCurrentTime ;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getSupportActionBar().hide();
        setContentView(R.layout.activity_media_player);
        initView();
    }

    private void initView() {
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // 螢幕常亮
        mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);
        mSurfaceHolder = mSurfaceView.getHolder();
        mSurfaceHolder.addCallback(new HoldCallback());
        mSeekBar = (SeekBar) findViewById(R.id.seekbar);
        mDurationTime = (TextView) findViewById(R.id.tv_duration_time);
        mCurrentTime= (TextView) findViewById(R.id.tv_current_time);
        seekBarListener();
    }

    private class HoldCallback implements SurfaceHolder.Callback {

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            Log.i(TAG, "--surfaceChanged");
        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            Log.i(TAG, "--surfaceCreated");
            String path = Environment.getExternalStorageDirectory().getPath()+"/yimaoshow/media/local/yimaosl.mp4";
            initMedia();
            if (mSurfaceHolder.getSurface().isValid()) {
                mMediaPlayer.reset();
                try {
                    // 設定音樂流
                    mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
                    // 設定播入檔案地址
                    mMediaPlayer.setDataSource(path);
                    mMediaPlayer.setDisplay(mSurfaceHolder);
                    mMediaPlayer.prepareAsync();

                } catch (IOException e) {

                }

            }
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            Log.i(TAG, "--surfaceDestroyed");
            if (mMediaPlayer != null) {
                if (mMediaPlayer.isPlaying()) {
                    mMediaPlayer.stop();
                    mMediaPlayer.release();
                    Log.d("VideoSurfaceView", "mMediaPlayer release");
                }
                mMediaPlayer = null;
            }
        }
    }

    private void initMedia() {
        if (mMediaPlayer == null) {

            mMediaPlayer = new MediaPlayer();
            mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {

                @Override
                public void onCompletion(MediaPlayer mp) {

                }
            });

            mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {

                @Override
                public boolean onError(MediaPlayer mp, int what, int extra) {
                    Log.i(TAG, "視訊播放中發生錯誤" + "what:"+what +"extra"+extra);
                    return false;
                }
            });

            mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {

                @Override
                public void onPrepared(MediaPlayer mp) {
                    Log.i(TAG, "視訊裝載完畢");
                    if (mMediaPlayer != null) {
                        mMediaPlayer.start();
                        mSeekBar.setMax(mMediaPlayer.getDuration());
                        mDurationTime.setText(mMediaPlayer.getDuration()/1000+"");
                        updateTime();
                    }

                }

            });
        }
    }

    private void updateTime() {
        if (mMediaPlayer != null) {
            mSeekBar.setProgress(mMediaPlayer.getCurrentPosition());
            mHandler.sendEmptyMessageDelayed(MESSAGE_UPDATE_TIME, 1000);
            mCurrentTime.setText(mMediaPlayer.getCurrentPosition()/1000 +"");
        }
    }

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MESSAGE_UPDATE_TIME:
                    updateTime();
                    break;
            }
        }
    };

    private void seekBarListener() {
        mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                mMediaPlayer.seekTo(seekBar.getProgress());
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

            }
        });

    }
}