The surface has been released when I try to setDisplay to MediaPlayer

后端 未结 6 657
忘掉有多难
忘掉有多难 2021-01-03 22:23

My xml file:



        
相关标签:
6条回答
  • 2021-01-03 23:00

    Make use of SurfaceHolder.Callback as below

    SurfaceView mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);
    SurfaceHolder holder = mSurfaceView.getHolder();
    final MediaPlayer player = new MediaPlayer();
    
    holder.addCallback(new SurfaceHolder.Callback() {
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            player.setDisplay(holder);
        }
    
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, 
        int height) {
    
        }
    
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
    
        }
    });
    
    String UrlPath="android.resource://"+getActivity().getPackageName()+"/"+R.raw.your_file_name_without_extension;
    try {
        player.setDataSource(getActivity(),Uri.parse(UrlPath));
        player.prepareAsync();
    } catch (IOException e) {
        e.printStackTrace();
    }
    player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
    
        @Override
        public void onPrepared(MediaPlayer mp) {
            mp.start();
        }
    });
    
    0 讨论(0)
  • 2021-01-03 23:00

    We can look at VideoView source code:

    SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback(){
    ...
        public void surfaceCreated(SurfaceHolder holder)
        {
            mSurfaceHolder = holder;
            openVideo();
        }
        private void openVideo() {
            ...
            mMediaPlayer = new MediaPlayer();
            mMediaPlayer.setDisplay(mSurfaceHolder);
        }
    }
    

    So we can learn that we should use mediaplayer.setDisplay() in surfaceCreate method be called.

    0 讨论(0)
  • 2021-01-03 23:11

    It's something related to the sequence of executing, as the surface has to be created first before setting display for the MediaPlayer, so you have to override the callback method surfaceCreated to the following:

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        mp.setDisplay(sh); // now "mp" is defined as a class variable
    }
    

    and now there is no need to setDisplay inside your play method:

    private MediaPlayer mp; // to use it inside surfaceCreated callback method
    public void playVideo() {
        mp = new MediaPlayer();
        SurfaceView sv = (SurfaceView) this.findViewById(R.id.surfaceView);
        try {
            mp.setDataSource("sdcard/test/a.3gp");
            SurfaceHolder sh = sv.getHolder();
            mp.prepare();
            mp.start();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    0 讨论(0)
  • 2021-01-03 23:13

    The Surface can be destroyed. That's why you need to add to the a public void surfaceDestroyed(SurfaceHolder holder) to your SurfaceView's implementation like this:

      @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        synchronized (this) {
            hasActiveHolder = false;
    
            synchronized(this)          {
                  this.notifyAll(); 
            }
        } 
    }
    

    You should also add a function that handles Surface creation:

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
         synchronized (this) {
            hasActiveHolder = true;
            this.notifyAll()
         }
    }
    

    And modify your own function this way:

        mp.setDataSource("sdcard/test/a.3gp");
        SurfaceHolder sh = sv.getHolder();
        synchronized (this) {
           while (!hasActiveHolder) {
                  try {
                      this.wait();
                  } catch (InterruptedException e) {
                    //Print something
                  }
            }
            mp.setDisplay(sh);
            mp.prepare();
        }
    

    You have another option which is the way Google suggests you use SurfaceView: in a separate thread.

    0 讨论(0)
  • 2021-01-03 23:19

    The simplest way is just to call setDisplay in surfaceCreated:

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        mp.setDisplay(holder)
    }
    

    and don't forget to unbind surface:

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mp.setDisplay(null);
    }
    

    Note: media player should be initialized somewhere before, for example in onCreate.

    0 讨论(0)
  • 2021-01-03 23:23

    For those still having issues, try implementing SurfaceHolder.Callback in your activity/fragment/etc and at the onCreate/onCreateView method, call the addCallback(SurfaceHolder.Callback callback) method, using your activity/fragment/etc as the parameter callback.

    0 讨论(0)
提交回复
热议问题