Make writing a habit together! This is the second day of my participation in the “Gold Digging Day New Plan · April More text challenge”. Click here for more details.

preface

After the implementation of MediaPlayer simple use, there are still many problems in the actual development, here to summarize the problem to record the cause and solution is the development summary.

The problem summary

TrackInfo Query resource information

Resources are loaded and executed during developmentprepareAsyncMethod to retrieve the resource TrackInfo in the callback method. It was hoped that this method could obtain the video size information, for exampleMediaExtractorThrough the method ofgetTrackFormatTo obtain resource information. TrackInfoInternally availableMediaFormatObject, but you’ll find the return in the actual source codeMediaFormatIs empty.

public MediaFormat getFormat(a) {
    if (mTrackType == MEDIA_TRACK_TYPE_TIMEDTEXT
            || mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
        return mFormat;
    }
    return null;
}
Copy the code

Therefore, in the use of MediaPlayer internal estimation can not directly obtain the resource file can only be obtained through MediaExtractor external.

Description Start failed after pause

MediaPlayerThe sequence diagram shows the method called, if it is calledpauseAnd then callstartThere is no problem. If the timingstopThe command must be executed againprepareMethod wait to reprepare resources and play again.

  • Question 1

The problem encountered in real development is that when the player Activity is in the background, the Activity calls the onStop method of the lifecycle, because the MediaPlayer lifecycle is bound to the page and also calls stop. MediaPlayer is now in the stop state, so we need to prepare for MediaPlayer again.

Problem 1: After the background is returned, the player can play the resource again, but the SurfaceView binding is a black screen.

  • Question 2

The bind SurfaceView black screen is essentially similar to problem 1. Because the SurfaceView also has a life cycle, when the Activity is in the background and the surfaceDestroyed is called, the original Surface bound to the SurfaceView and player has become invalid and needs to be bound again.

The original logic is to initialize and bind only once in the POST method, so binding only in the POST method is not appropriate.

surfaceView.post(new Runnable() {
    @Override
    public void run(a) {
        AndroidMediaPlayer.Builder builder = new AndroidMediaPlayer.Builder(TestSimpleMediaPlayerActivity.this,uri,listener); builder.withSurface(surfaceView.getHolder().getSurface()); androidMediaPlayer = builder.createPlayer(); androidMediaPlayer.prepareAsync(); }});Copy the code

SurfaceCreated performs Surface binding from the surfaceView callback method to ensure that the binding is refreshed every time the page is entered from behind the scenes.

surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
    @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder) {
        if(androidMediaPlayer ! =null)
        androidMediaPlayer.setSurface(surfaceView.getHolder().getSurface());
    }

    @Override
    public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
        Log.d("<> surfaceView"."surfaceChanged");

    }

    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
        Log.d("<> surfaceView"."surfaceDestroyed"); }});Copy the code
  • Question 3

Another problem with MediaPlayer is that it does not provide a playback progress callback interface. MediaPlayer has the getCurrentPosition method to retrieve the current playback progress, but it does not encapsulate the ability to provide real-time access, so developers need to implement real-time access methods.

The player getCurrentPosition method is repeatedly called by Thread to obtain the current playing millisecond value. In addition, delay processing can be added according to actual business needs.

private class PlayerThread extends Thread{
    private boolean toGet = false;
    public void startGet(a){
        toGet = true;
    }
    public void stopGet(a){
        toGet = true;
    }
    @Override
    public void run(a) {
        super.run();
        while (toGet){
            if(mMediaPlayer ! =null) {int position =  mMediaPlayer.getCurrentPosition();
               if(mListener ! =null){
                   playerInfo.playerProgress = position;
                   mListener.onPlayerInfoCallBack(playerInfo);
               }
            }
        }
    }
}
Copy the code

conclusion

MediaPlayer is simple to use, but some details emerge during implementation development. There are still a number of scenarios that need to be refined and considered in order to truly develop and implement the full player functionality, but MediaPlayer still has some underlying capabilities that can be mined.