最好的答案是简单地用一个TextureView而不是SurfaceView的(一个VideoView从SurfaceView默认继承)。要做到这一点,使用的代码如下:
定义您TextureView在activity_main.xml
:
<TextureView
android:id="@+id/videoTexture"
android:layout_width="match_parent"
android:layout_height="match_parent />
在你MainActivity.java
,声明以下变量:
private MediaPlayer mMediaPlayer;
private TextureView mVideoTextureView;
private float mDisplayWidth;
private float mDisplayHeight;
然后在您的onCreate()
方法,对它们进行初始化如下:
mVideoTextureView =(TextureView) rootview.findViewById(R.id.videoTexture);
mVideoTextureView.setSurfaceTextureListener(this);
mMediaPlayer = new MediaPlayer();
loadNewMovie();
要加载影片到的MediaPlayer,请使用以下代码:
private void loadNewMovie() {
AssetFileDescriptor afd = this.getResources().openRawResourceFd(ID_OF_YOUR_MOVIE);
try {
// Set source
mMediaPlayer.reset();
mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getDeclaredLength());
mMediaPlayer.prepare();
/*
// Gets the Height/Width of the video but does NOT include space
// taken up by black bars if the dimensions don't exactly fit the screen.
MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
metaRetriever.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
String height = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
String width = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
mVideoHeight = Float.parseFloat(height);
mVideoWidth = Float.parseFloat(width);
*/
// Gets the size of the display in pixels (used for scaling)
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
mDisplayWidth = size.x;
mDisplayHeight = size.y;
// Play movie
if (currState == State.PLAYING)
mMediaPlayer.start();
afd.close();
}
catch (Exception e) {
Log.e("ERROR", "loadNewMovie: " + e.getMessage(), e);
}
mMediaPlayer.seekTo(DEFAULT_VIDEO_INIT_POSITION);
}
最后,您的视频可以即时使用下面的代码调整:
private void updateTextureViewSize(int viewWidth, int viewHeight) {
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(viewWidth,viewHeight);
// ANY OTHER RULES...EXAMPLE:
// params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
mVideoTextureView.setLayoutParams(params);
}
或者你可以动画这样的变化:
private void animateTextureViewScaling(final float startScaleX, final float startScaleY,
final float endScaleX, final float endScaleY,
int duration) {
// Note: Can't just use .scaleX and .scaleY directly because it will only scale
// the video, not it's holder
mVideoTextureView.animate().setDuration(duration)
.setUpdateListener(new AnimatorUpdateListener() {
float value, scalingX, scalingY;
float changeXScale = startScaleX - endScaleX;
float changeYScale = startScaleY - endScaleY;
@Override
public void onAnimationUpdate(ValueAnimator animation) {
value = (Float) animation.getAnimatedValue();
scalingX = (float) (startScaleX - changeXScale*value);
scalingY = (float) (startScaleX - changeYScale*value);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
(int) (mDisplayWidth*scalingX), (int) (mDisplayHeight*scalingY));
// ANY OTHER RULES...EXAMPLE:
// params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
mVideoTextureView.setLayoutParams(params);
}
}).start();
}
在上面的代码中,我用mDisplayWidth
(在loadNewVideo()
组)为我视频的原始大小。你可以使用任何你想要的。
好处这是一个TextureView可以动画,转换和缩放(SurfaceView不能)。
缺点是一个TextureView只能用于硬件加速窗口,并会比SurfaceView使用更多的内存(大约30%)。它也可能经历1到3帧的延迟。
你错过了这段代码中的重要部分......(我认为)。您还应该将MediaPlayer设置为使用TextureView。可能在SurfaceTextureListener的onSurfaceTextureAvailable方法中。 –