MediaPlay+SurfaceView realizes playing video

1. Introduce the common methods of MediaPlay class and SurfaceView:

Common methods of the MediaPlay class:

Method name function
void seDataSource(String path) set data source (http/rtsp address)
void seDataSource(FileDescriptor fd,long offset,long length ) Set data source
void seDataSource(Context context,Uri uri) Set a Uri data source
static MediaPlayercreate(Context context,int resid) Conveniently create MediaPlayer according to a given resource id Object method
static MediaPlayercreate(Context context,Uri uri,SurfaceHolder holder) Create a MediaPlayer object according to a given URI
boolean isPlaying() Determine whether MediaPlayer is playing
getCurrentPosition() Get the current position Play position
getDuration() Get the time of the file
isLooping(boolean b) Whether to play in a loop
getVideoHeight(), getVideoWidth() Get the width and height of the video
pause() Pause
prepare() Prepare (synchronous)
prepareAsync() Prepare (asynchronous)
release() Release the MediaPlayer object Related Resources
reset() Reset the MediaPlayer object to the state it just created
seekTo(int seek) Specify the playback position (time in milliseconds)
setAudioStreamType(int type) Set the type of streaming media
setDisplay(SurfaceHolder sh) Set SurfaceHolder to display multimedia
stop() Stop playing
setVolume(float leftVolume,float rightVolume) Set volume
setScreenOnWhilePlaying(boolean b) Set whether to use SurfaceHolder to keep the screen displayed
start() Start playing

Monitoring method:

setOnButteringUpdateListener Internet streaming media buffer monitoring
setOnErrorListener setting error Information monitoring
setOnVideoSizeChangedListener Video size monitoring

Common methods of the SurfaceView class:

Construction method

Function

purblic SurfaceView(Context context) Create a SurfaceView object
purblic SurfaceView (Context context, AttributeSet attrs) Create SurfaceView object
purblic SurfaceView(Context context, AttributeSet attrs, int defStyle) Create a SurfaceView object
Common methods Function
public SurfaceHolder getHolder() Get the SurfaceHolder object to manage surfaceview
public void setVisibility(int visibility) Set whether it is visible

SurfaceHolder is an interface, similar to a Surface listener. There are three callback methods to monitor the creation, destruction and change of Surface.

 @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder) {
          // create
    }

    @Override
    public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
          // Change
    }

    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
           // destroy
    }

2. Example:

MainActivity:

package com.example.surfaceview;

import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.content.ContentResolver;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.Toast;

import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener,SurfaceHolder.Callback, View.OnClickListener {
    private SurfaceView sv;
    private SurfaceHolder mHolder;
    private MediaPlayer mPlayer;
    private RelativeLayout rl;
    private Timer mTimer;
    private TimerTask mTimerTask;
    private SeekBar sbar;
    private ImageView play, forward, backward, loop;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R. layout. activity_main);
        initView();
        mTimer = new Timer();
        // The task of the timer:
        mTimerTask = new TimerTask() {
            @Override
            public void run() {
                if (mPlayer!=null & &mPlayer.isPlaying()){
                    // Get the length of the video and set the maximum value of the progress bar
                    int total = mPlayer. getDuration();
                    sbar.setMax(total);
                    // get the current position
                    int progress = mPlayer. getCurrentPosition();
                    sbar.setProgress(progress);
                }
            }
        };
        // start the timer
        mTimer.schedule(mTimerTask,500,500);
    }

    private void initView() {
        sv = findViewById(R.id.sv);
        loop = findViewById(R.id.loop_Im);
        loop.setOnClickListener(this);
        forward = findViewById(R.id.backward_Im);
        forward.setOnClickListener(this);
        backward = findViewById(R.id.forward_Im);
        backward. setOnClickListener(this);
        // Get the SurfaceHolder object for managing SurfaceView
        mHolder = sv. getHolder();
        mHolder. setType(3);
        mHolder. addCallback(this);
        rl = findViewById(R.id.rl);
        play = findViewById(R.id.play);
        play.setOnClickListener(this);
        sbar = findViewById(R.id.sbar);
        sbar.setOnSeekBarChangeListener(this);
    }


    @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder) {
        mPlayer = new MediaPlayer();
        mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        Uri uri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
                getPackageName() + "/" + R.raw.video);
        try {
            // set the data source
            mPlayer.setDataSource(MainActivity.this,uri);
            // surfaceView is associated with MediaPlay
            mPlayer.setDisplay(mHolder);
            mPlayer.prepareAsync(); // Prepare to play (asynchronous)
            mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    mPlayer.start();
                }
            });
        }catch (Exception e){
            Toast.makeText(MainActivity.this,"Play failed!",Toast.LENGTH_LONG).show();
            e.printStackTrace();
        }

    }

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

    }

    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
        if (mPlayer!=null)
            mPlayer. stop();
    }
    /

    // When the progress of the progress bar changes
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        if (seekBar. getProgress()==seekBar. getMax()){
            play.setBackgroundResource(R.drawable.stop);
            
        }
    }
    // Triggered when the progress bar is dragged
    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {

    }
        // Triggered when the progress bar stops dragging
    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
        int position = seekBar. getProgress();
        if (mPlayer!=null){
            mPlayer. seekTo(position);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event. getAction()){
            case MotionEvent. ACTION_DOWN:
                if (rl. getVisibility() == INVISIBLE) {
                    rl. setVisibility(VISIBLE);
                    CountDownTimer cdt = new CountDownTimer(3000, 1000) {
                        @Override
                        public void onTick(long millisUntilFinished) {
                            System.out.println(millisUntilFinished);
                        }

                        @Override
                        public void onFinish() {
                            // hide progress bar and play button
                            rl. setVisibility(INVISIBLE);
                        }
                    };
                    cdt.start();
                }else if(rl. getVisibility() == VISIBLE){
                rl. setVisibility(INVISIBLE);
            }
                break;
        }
        return super.onTouchEvent(event);
    }

    @Override
    protected void onDestroy() {
        // Release resources
        mTimerTask. cancel();
        mTimer. cancel();
        mTimer = null;
        mTimerTask = null;
        mPlayer. release();
        mPlayer=null;
        super. onDestroy();
    }

    @Override
    public void onClick(View v) {
        switch (v. getId()){
            case R.id.backward_Im:
                int bPosition = mPlayer.getCurrentPosition()-100;
                mPlayer.seekTo(bPosition);
                sbar.setProgress(bPosition);
                break;
            case R.id.forward_Im:
                int fPosition = mPlayer.getCurrentPosition() + 200;
                mPlayer.seekTo(fPosition);
                sbar.setProgress(fPosition);
                break;
            case R.id.loop_Im:

                if (mPlayer.isPlaying()){
                    loop.setBackgroundResource(R.drawable.floooping);
                    Toast.makeText(this, "1111", Toast.LENGTH_SHORT).show();
                    mPlayer. setLooping(false);
                } else {
                    loop.setBackgroundResource(R.drawable.tlooping);
                    Toast.makeText(this, "1222", Toast.LENGTH_SHORT).show();
                    mPlayer. setLooping(true);
                }
                break;
            case R.id.play:
                if (mPlayer!=null & &mPlayer.isPlaying()){
                    mPlayer. pause();
                    play.setImageResource(R.drawable.stop);
                } else {
                    mPlayer.start();
                    play.setImageResource(R.drawable.start);
                }
                break;
        }
    }
}

activity_main:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    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">
    <SurfaceView
        android:id="@ + id/sv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
    <RelativeLayout
        android:id="@ + id/rl"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >

        <SeekBar
            android:id="@ + id/sbar"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:max="100"
            android:progress="0" />

        <ImageView
            android:id="@ + id/play"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_centerInParent="true"
            android:background="@drawable/start" />

        <ImageView
            android:id="@ + id/backward_Im"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_centerInParent="true"
            android:layout_toLeftOf="@ + id/play"
            android:background="@drawable/backward" />

        <ImageView
            android:id="@ + id/forward_Im"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_toRightOf="@ + id/play"
            android:layout_centerInParent="true"
            android:background="@drawable/forward" />

        <ImageView
            android:id="@ + id/loop_Im"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_below="@ + id/forward_Im"
            android:layout_centerInParent="true"
            android:background="@drawable/floooping" />
    </RelativeLayout>
</FrameLayout>