I wish to keep buffered portions of video which is played in a VideoView
. I found out that the VideoView
's SurfaceDestroyed
has release(true);
call, caused releasing of mMediaPlayer
instance according to this question VideoView onResume loses buffered portion of the video
I don't want to hack into the internal API so I decides to rewrite SurfaceHolder.Callback
and replace it to the mSHCallback
field instead to avoid calling release(true);
using reflection.
But it seems very strange when I call VideoView.start()
in SurfaceCreated
override, I've got "Can't play this video' message multiple times but the audio is continue playing through the end even I switch to other activity.
Here is my custom callback
package com.tirkx.aos;
import android.util.Log;
import android.widget.MediaController;
import android.media.MediaPlayer;
import android.view.SurfaceHolder;
import android.widget.VideoView;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class CustomVidViewCallbackLoader implements SurfaceHolder.Callback
{
private final String TAG = "CustomCallbackLoader";
private Map<String, Field> PrivateFields;
private Map<String, Method> PrivateMethods;
private VideoView VideoView;
boolean VideoOpened;
public CustomVidViewCallbackLoader(VideoView videoView)
{
VideoView = videoView;
PrivateFields = new HashMap<String, Field>();
PrivateMethods = new HashMap<String, Method>();
Class VideoViewClass = videoView.getClass();
//Reflection things
try
{
PrivateFields.put("mSHCallback", VideoViewClass.getDeclaredField("mSHCallback"));
PrivateFields.put("mSurfaceHolder", VideoViewClass.getDeclaredField("mSurfaceHolder"));
PrivateFields.put("mMediaController", VideoViewClass.getDeclaredField("mMediaController"));
PrivateFields.put("mMediaPlayer", VideoViewClass.getDeclaredField("mMediaPlayer"));
PrivateFields.put("mSurfaceWidth", VideoViewClass.getDeclaredField("mSurfaceWidth"));
PrivateFields.put("mSurfaceHeight", VideoViewClass.getDeclaredField("mSurfaceHeight"));
PrivateFields.put("mTargetState", VideoViewClass.getDeclaredField("mTargetState"));
PrivateFields.put("mVideoWidth", VideoViewClass.getDeclaredField("mVideoWidth"));
PrivateFields.put("mVideoHeight", VideoViewClass.getDeclaredField("mVideoHeight"));
PrivateFields.put("mSeekWhenPrepared", VideoViewClass.getDeclaredField("mSeekWhenPrepared"));
PrivateMethods.put("openVideo", VideoViewClass.getDeclaredMethod("openVideo"));
for(Map.Entry<String, Method> m : PrivateMethods.entrySet())
m.getValue().setAccessible(true);
for(Map.Entry<String, Field> f : PrivateFields.entrySet())
f.getValue().setAccessible(true);
}
catch(Exception ex)
{
ex.printStackTrace();
}
try
{
SurfaceHolder.Callback SHCallback = (SurfaceHolder.Callback) PrivateFields
.get("mSHCallback").get(videoView);
if (SHCallback != null)
{
videoView.getHolder().removeCallback(SHCallback);
PrivateFields.get("mSHCallback").set(videoView, this);
videoView.getHolder().addCallback((SurfaceHolder.Callback) PrivateFields
.get("mSHCallback").get(videoView));
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
@Override
public void surfaceCreated(SurfaceHolder holder)
{
try
{
PrivateFields.get("mSurfaceHolder").set(VideoView, holder);
if(!VideoOpened)
{
PrivateMethods.get("openVideo").invoke(VideoView);
VideoOpened = true;
}
else
{
VideoView.start();
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
try
{
//PrivateFields.get("mSurfaceHolder").set(VideoView, holder);
int mVideoWidth = (int) PrivateFields.get("mVideoWidth").get(VideoView);
int mVideoHeight = (int) PrivateFields.get("mVideoHeight").get(VideoView);
int mTargetState = (int) PrivateFields.get("mTargetState").get(VideoView);
int mSeekWhenPrepared = (int) PrivateFields.get("mSeekWhenPrepared").get(VideoView);
MediaPlayer mMediaPlayer = (MediaPlayer) PrivateFields.get("mMediaPlayer").get(VideoView);
PrivateFields.get("mSurfaceWidth").set(VideoView, width);
PrivateFields.get("mSurfaceHeight").set(VideoView, height);
boolean isValidState = (mTargetState == 3);
boolean hasValidSize = (mVideoWidth == width && mVideoHeight == height);
if(mMediaPlayer != null && isValidState && hasValidSize)
{
if(mSeekWhenPrepared != 0)
VideoView.seekTo(mSeekWhenPrepared);
VideoView.start();
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder)
{
try
{
PrivateFields.get("mSurfaceHolder").set(VideoView, null);
MediaController mediaController = (MediaController) PrivateFields.get("mMediaController")
.get(VideoView);
if(mediaController != null)
mediaController.hide();
VideoView.pause();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
public void setMediaPlayerOnBufferedChanged(MediaPlayer mediaPlayer)
{
if (mediaPlayer != null)
{
mediaPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener()
{
@Override
public void onBufferingUpdate(MediaPlayer mp, int percent)
{
Log.i(TAG, "-->" + percent);
}
});
}
}
}
Aucun commentaire:
Enregistrer un commentaire