VideoView onResume loses buffered portion of the video

后端 未结 10 501
北恋
北恋 2020-12-01 02:56

I am having an Activity in which there is

  1. VideoView -- Streams a video from a webserver.

  2. Button -- Takes the user to the next activit

相关标签:
10条回答
  • 2020-12-01 03:30

    Have you tried seekto()

    @Override
    protected void onResume() {
        super.onResume();
        try{
            if (video_view != null) {
                video_view.seekTo(position);    
                video_view.start();
            }
        }catch (Exception e) {
                    }
    }
    
    @Override
    protected void onPause() {
        super.onPause();    
        try{
            if (video_view != null) {
                position = video_view.getCurrentPosition();
                video_view.pause();         
            }
        }catch (Exception e) {
                    }
    }
    
    0 讨论(0)
  • 2020-12-01 03:33
    public class Video_play extends Activity {
        VideoView vv;
       String URL;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);
            setContentView(R.layout.play_video);
            URL= getIntent().getStringExtra("URL");
    
            vv=(VideoView)findViewById(R.id.videoView1);
            MediaController mediaController = new MediaController(this);
            mediaController.setAnchorView(vv);
            Log.v("URL",URL);
    
    
    //       Uri uri = Uri.parse(URL);
    //        vv.setVideoURI(uri);
            vv.setMediaController(new MediaController(this));
            vv.setVideoPath(URL);
    
    //        vv.requestFocus();
    //       
    //        vv.start();
    
    
    //      Uri uri=Uri.parse(URL);
    //
    //    
    //      vv.setVideoURI(uri);
            vv.start();
        }
    
    0 讨论(0)
  • 2020-12-01 03:36

    I've worked out a version that does not require a custom VideoView or manual configuration change handling. See Android VideoView orientation change with buffered video for an explanation.

    0 讨论(0)
  • 2020-12-01 03:38

    I found a solution fix it:

    VideoView videoView;
    MediaPlayer mp;
    
    videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    this.mp = mp;
                }
            });
    
    public void pause(){
        //NOT videoview.pause();
        if (mp != null){
           mp.pause();
        }
    }
    
    public void resume(){
        //NOT videoview.resume();
        if (mp != null){
           mp.start();
        }   
    }
    

    It work for me, i sure it help you

    0 讨论(0)
  • 2020-12-01 03:41

    I've spent several hours trying to hack the original VideoView source code and Now I can confirm VideoView can be hacked to behavior what you want - retain buffering after surface destroyed. I've tested on my Samsung Galaxy S2, which works as expected, in my case, the video buffering (streaming m4v video from remote http server) is successfully retained when I open a new activity and go back.

    Basically, the workaround is create you own VideoView class (by copying the source code), and hack the SurfaceHolder.Callback() implementation. Bear in mind that VideoView use some internal/hide API, so if you want to create a copy of VideoView in your own project, you have to follow the inazaruk's article to enable using internal/hide API. As a quick hack, I just download inazaruk's build from here and use inazaruk-android-sdk-dbd50d4/platforms/android-15-internals/android.jar replace my original android.jar in my android-sdk/platforms/android-15/.

    VideoView source code can be downloaded from GrepCode. Once you successfully create you own copy without compile error, change SurfaceHolder.Callback() to something like this:

    private boolean videoOpened = false;
    
    SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback()
    {
    
        ... ...
    
        public void surfaceCreated(SurfaceHolder holder)
        {
            Log.i(TAG, "---------------------> surface created.");
            mSurfaceHolder = holder;
            if (!videoOpened) {
              openVideo(); // <-- if first time opened, do something as usual, video is buffered.
              /** 
               * openVideo() actually mMediaPlayer.prepareAsync() is the first key point, it is
               * also called in other two VideoView's public methods setVideoURI() and resume(), 
               * make sure you don't call them in your activity.
               */ 
              videoOpened = true;
            } else {
              start();  // <-- if back from another activity, simply start it again.
            }
        }
    
        public void surfaceDestroyed(SurfaceHolder holder)
        {
            Log.i(TAG, "---------------------> surface destroyed.");
            // after we return from this we can't use the surface any more.
            mSurfaceHolder = null;
            if (mMediaController != null) mMediaController.hide();
            //release(true);
            /**
             * release() actually mMediaPlayer.release() is the second key point, it is also
             * called in other two VideoView's public methods stopPlayback() and suspend(), make
             * sure you don't call them in your activity.
             */
            pause(); // <-- don't release, just pause.
        }
    };
    

    And make sure you don't call videoView.resume(), videoView.setVideoURI(), videoView.suspend() and videoView.stopPlayback() explicitly in you MediaPlayerActivity like this:

    @Override
    protected void onResume() {
      if (videoView != null)
        videoView.resume();  // <-- this will cause re-buffer.
        super.onResume();
    }
    
    @Override
    protected void onPause() {
      if (videoView != null)
        videoView.suspend(); // <-- this will cause clear buffer.
        super.onPause();
    }
    

    Note that I have just done a dirty hack to prove the feasibility, You should design and implement your VideoView class properly to avoid any side-effect.

    Update:

    As an alternative, you should able to achieve same effect using plain MediaPlayer create your MediaPlayerActivity if you don't want to do the interal/hide API stuff You can start with the MediaPlayerDemo_Video.java in ApiDemos sample. The key point is make sure prepare (result buffering) and release method is properly handled in both SurfaceHolder Callback methods and Activity life cycle method to avoid prepare/release video every time surface is created/destroyed, and Activity is started,resumed/paused,stopped. I've created a dummy BufferedMediaPlayerActivity (highly simplified for posting here) which contains only key parts and can be used for quick demonstration, it doesn't have MediaController, however, you can check from Logcat to see that the buffer percentage is actually keep increasing instead of rolling over from 0 every time you open new activity and go back.

    BufferedMediaPlayerActivity.java:

    package com.example;
    
    import android.media.AudioManager;
    import android.media.MediaPlayer;
    import android.media.MediaPlayer.OnBufferingUpdateListener;
    import android.media.MediaPlayer.OnPreparedListener;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    
    public class BufferedMediaPlayerActivity extends Activity implements OnPreparedListener, OnBufferingUpdateListener, SurfaceHolder.Callback {
    
      private static final String TAG = "BufferedMediaPlayerActivity";
      private int mVideoWidth;
      private int mVideoHeight;
      private MediaPlayer mMediaPlayer;
      private SurfaceView mPreview;
      private SurfaceHolder holder;
      private String path;
      private boolean mIsVideoReadyToBePlayed = false;
    
      @Override
      public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.buffered_media_player);
        mPreview = (SurfaceView) findViewById(R.id.surface);
        holder = mPreview.getHolder();
        holder.addCallback(this);
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        holder.setFixedSize(mVideoWidth, mVideoHeight);
        // retrieve httpUrl passed from previous activity.
        path = getIntent().getExtras().getString("videoUrl");
      }
    
      @Override
      public void onDestroy() {
        super.onDestroy();
        if (mMediaPlayer != null) {
          mMediaPlayer.release();
          mMediaPlayer = null;
        }
        mIsVideoReadyToBePlayed = false;
      }
    
      private void playVideo() {
        mIsVideoReadyToBePlayed = false;
        try {
          // Create a new media player and set the listeners
          mMediaPlayer = new MediaPlayer();
          mMediaPlayer.setDataSource(path);
          mMediaPlayer.setDisplay(holder);
          mMediaPlayer.prepare();
          mMediaPlayer.setOnPreparedListener(this);
          mMediaPlayer.setOnBufferingUpdateListener(this);
          mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        } catch (Exception e) {
          Log.e(TAG, "error: " + e.getMessage(), e);
        }
      }
    
      @Override
      public void onPrepared(MediaPlayer mediaplayer) {
        Log.d(TAG, "onPrepared called");
        mIsVideoReadyToBePlayed = true;
        if (mIsVideoReadyToBePlayed) {
          mMediaPlayer.start();
        }
      }
    
      @Override
      public void onBufferingUpdate(MediaPlayer mp, int percent) {
        Log.i(TAG, "---------------> " + percent);
      }
    
      @Override
      public void surfaceChanged(SurfaceHolder surfaceholder, int i, int j, int k) {
        Log.d(TAG, "surfaceChanged called");
      }
    
      @Override
      public void surfaceCreated(SurfaceHolder holder) {
        Log.d(TAG, "surfaceCreated called");
        if (!mIsVideoReadyToBePlayed)
          playVideo();
        else
          mMediaPlayer.start();
      }
    
      @Override
      public void surfaceDestroyed(SurfaceHolder surfaceholder) {
        Log.d(TAG, "surfaceDestroyed called");
        mMediaPlayer.pause();
      }
    
    }
    

    buffered_media_player.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:orientation="vertical"
      android:layout_width="match_parent"
      android:layout_height="match_parent">
    
      <SurfaceView android:id="@+id/surface"
        android:layout_width="200dip"
        android:layout_height="160dip"
        android:layout_gravity="center">
      </SurfaceView>
    
    </LinearLayout>
    
    0 讨论(0)
  • 2020-12-01 03:42

    You've mentioned two separate problems, and while I don't know how to keep the buffered video, You can still avoid starting from the beginning by calling getCurrentPosition in onPause and seekTo on onResume. This call is asynchronous, but it might give you a partial solution.

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