Android使用SurfaceView播放视频 简单介绍

本文介绍了如何在Android应用中使用SurfaceView来播放视频,相较于VideoView,SurfaceView提供了更灵活的控制。首先展示SurfaceView的使用代码,然后在Activity中实现SurfaceHolder.Callback接口来操作视频播放。虽然这种方式需要更多的自定义工作,但能更好地进行视频显示的定制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android中播放视频,简单就直接用VideoView,这是系统集成的一个视频播放组件,使用起来还是比较方便的。

这里要写的是使用SurfaceView播放视频,SurfaceView的方便之处我不再多说,具体使用方法如下。

直接上代码:

布局文件长这样:

<?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"
android:background="@color/color_black">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true">

        <SurfaceView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/video_surfaceview"
            android:layout_centerInParent="true">
        </SurfaceView>

        <LinearLayout
            android:orientation="vertical"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/layout_loading"
            android:gravity="center"
            android:visibility="visible"
            android:layout_centerInParent="true">

            <ProgressBar
                style="?android:attr/progressBarStyleSmall"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/progressBar3" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="正在加载..."
                android:id="@+id/tv_loading"
                android:textColor="@color/color_white"
                android:layout_marginLeft="5dp" />

        </LinearLayout>
    </RelativeLayout>

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="#88000000"
        android:padding="5dp"
        android:gravity="center_vertical">

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/btn_play"
            android:src="@mipmap/media_pause_ic" />

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingLeft="10dp"
            android:paddingRight="5dp"
            android:layout_marginLeft="10dp">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="00:00"
                android:id="@+id/tv_end_time"
                android:textColor="@color/color_white"
                android:layout_marginLeft="5dp"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true" />

            <SeekBar
                android:id="@+id/seekBar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                style="@style/Widget.SeekBar.Normal"
                android:layout_toLeftOf="@+id/tv_end_time"
                android:layout_centerVertical="true" />


        </RelativeLayout>


    </LinearLayout>

</RelativeLayout>

然后在Activity中使用,用SurfaceHolder.Callback,不多说,直接上代码:

大致内容是这样的:

public class MediaPlayActivity extends Activity implements SurfaceHolder.Callback{
public static final String NATIVE_MEDIA_URLS = "native_media";
private  MediaPlayer mMediaPlayer;
private SurfaceView mPreview;
private SurfaceHolder mHolder;
private boolean isShow = false;

private ImageView btnPlay;
private SeekBar mSeekBar;
private TextView tvEndTime;
private Timer mTimer;
private int surfaceWidth,surfaceHeight;

private View loadingView;
private TextView tvLoading;
private  String mediaUrl;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    this.setContentView(R.layout.screen_media_player);
    isShow = true;
    mediaUrl = getIntent().getStringExtra("mediaUrl");
    registerComponent();


}
private void registerComponent(){

    mPreview = (SurfaceView)findViewById(R.id.video_surfaceview);
    mPreview.setFocusable(true);

    mHolder = mPreview.getHolder();
    mHolder.addCallback(this);
    btnPlay = (ImageView)this.findViewById(R.id.btn_play);
    btnPlay.setImageResource(R.mipmap.media_pause_ic);
    btnPlay.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (isPlaying()) {
                pauseMedia();
            } else {
                replayMedia();
            }
            setMediaPlayerStatus(isPlaying());
        }
    });

    mSeekBar = (SeekBar)this.findViewById(R.id.seekBar);
    mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
            if (mMediaPlayer != null) {
                mMediaPlayer.seekTo(seekBar.getProgress() * 1000);
            }
            setMediaPlayerStatus(isPlaying());
        }
    });
    tvEndTime = (TextView)this.findViewById(R.id.tv_end_time);


    loadingView = this.findViewById(R.id.layout_loading);
    loadingView.setVisibility(View.GONE);

    tvLoading = (TextView)this.findViewById(R.id.tv_loading);
}


private void setMediaPlayerStatus(boolean playing){
    if(playing){
        btnPlay.setImageResource(R.mipmap.media_pause_ic);
    }else{
        btnPlay.setImageResource(R.mipmap.media_play_ic);
    }
}
private void setProgress(int duration,int max){

    int time = (max-duration)/1000;
    mSeekBar.setMax(max / 1000);
    if(duration<50)
        mSeekBar.setProgress(0);
    else
    mSeekBar.setProgress((duration / 1000)+1);
    tvEndTime.setText(String.format("%02d", time / 60) + ":" + String.format("%02d", time));
}


private void startTimer(){

    if(mTimer == null){
        mTimer = new Timer();
    }
    setProgress(-1, mMediaPlayer.getDuration());
    mTimer.schedule(new TimerTask() {
        @Override
        public void run() {
            if (isPlaying()) {
                mHandler.sendEmptyMessage(0);
            }
        }
    }, 0, 1000);
}

private Handler mHandler = new Handler(){

    public void handleMessage(Message msg){
        setProgress(mMediaPlayer.getCurrentPosition(),mMediaPlayer.getDuration());
    }
};

private void initMedia(Uri uri){

    mMediaPlayer = new MediaPlayer();
    mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mediaPlayer) {

            setMediaPlayerStatus(false);
            setProgress(-1, mMediaPlayer.getDuration());
            //mMediaPlayer.seekTo(500);
        }
    });
    mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
        @Override
        public boolean onError(MediaPlayer mediaPlayer, int whatError, int extra) {

            Toast("播放失败");
            releaseMedia();
            return true;
        }
    });


    mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mediaPlayer) {

            resetDisplay(mWidth, mHeight);
            //setProgress(mMediaPlayer.getCurrentPosition()+1, mMediaPlayer.getDuration());


            loadingView.setVisibility(View.GONE);
            setMediaPlayerStatus(true);
        }
    });

    mMediaPlayer.setDisplay(mHolder);
}


private  void resetDisplay(int width,int height){

    int vWidth = mMediaPlayer.getVideoWidth();
    int vHeight = mMediaPlayer.getVideoHeight();

    float scale = 1.0f * width / vWidth;
    if (vWidth < vHeight) {
        scale = 1.0f * height / vHeight;
    }

    RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams((int) (vWidth * scale), (int) (vHeight * scale));
    params.addRule(RelativeLayout.CENTER_HORIZONTAL);
    params.addRule(RelativeLayout.CENTER_VERTICAL);
    mPreview.setLayoutParams(params);

    mMediaPlayer.setDisplay(mHolder);
}



private void playMedia(Uri uri){
    if(mMediaPlayer == null){
        initMedia(uri);
    }
    mMediaPlayer.reset();
    try {
        mMediaPlayer.setDataSource(this, uri);
        mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        mMediaPlayer.prepare();
        startTimer();
        mMediaPlayer.start();


    }catch(Exception e){
        e.printStackTrace();
        Toast("播放失败");
    }
}


private void pauseMedia(){

    if (mMediaPlayer != null) {
        mMediaPlayer.pause();
    }
}

private void replayMedia(){

    if(mMediaPlayer != null){
        mMediaPlayer.start();
    }
}


private boolean isPlaying(){

    if(mMediaPlayer != null){
            return mMediaPlayer.isPlaying();
    }
    return false;
}


private void releaseMedia(){
    if(mTimer != null){
        mTimer.cancel();
        mTimer = null;
    }
    if (mMediaPlayer != null) {
        mMediaPlayer.release();
        mMediaPlayer = null;
    }
}
public void surfaceCreated(SurfaceHolder holder) {
    // TODO Auto-generated method stub
   //播放本地视频

       playMedia(Uri.fromFile(new File(mediaUrl)));
  //若是网络视频,可先下载,然后播放
}

public void surfaceChanged(SurfaceHolder arg0, int format, int width, int height) {
    // TODO Auto-generated method stub

    this.surfaceWidth = width;
    this.surfaceHeight = height;

}

public void surfaceDestroyed(SurfaceHolder holder) {
    // TODO Auto-generated method stub
    releaseMedia();
}
public void onPause(){
    isShow = false;
    super.onPause();
    pauseMedia();
    setMediaPlayerStatus(isPlaying());
}


public void onDestroy(){
    super.onDestroy();
    releaseMedia();
}
}

如此便可以使用surfaceview来播放视频了。其中细节不到位之处,只能自行补全。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值