我正面临Android MediaPlayer
类的一个奇怪问题。我使用MediaPlayer在VideoView中播放视频。这适用于所有设备,除了Android 4.2.2的三星GT-I8200N。那么,我确实听说过这些视频不能在某些三星4.1.X设备上播放,但我无法获得这些设备中的一种。我在Google Android模拟器中没有遇到任何错误。在Android 4.2.2上播放视频时Android MediaPlayer会闪烁
一些更多的细节:Android 4.2.2的三星GT-I8200N能够在一个片段中播放视频,但不能在另一个片段中播放,即使使用相同的代码播放视频。当视频开始播放时,除了视频应该在的空间以外,整个屏幕都会呈现黑色。
下面是代码:
public abstract class AbstractSignVideoFragment extends Fragment {
private static final double MAXMIMUM_VIDEO_HEIGHT_ON_LANDSCAPE = 0.4;
private static final double MAXIMUM_VIDEO_WIDTH_ON_PORTRAIT = 0.8;
private final static String TAG = AbstractSignVideoFragment.class.getSimpleName();
private static final String ANDROID_RESOURCE = "android.resource://";
private static final String SLASH = "/";
private static final String RAW = "raw";
protected VideoView videoView;
protected ProgressBar progressBar;
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
protected boolean isSetupVideoViewSuccessful(final Sign sign, final SOUND sound, final CONTROLS controls) {
initializeMediaController();
final String mainActivityPackageName = getActivity().getPackageName();
final int signIdentifier = getActivity().getResources().getIdentifier(sign.getName(), RAW, mainActivityPackageName);
if (0 == signIdentifier) {
return false;
}
final Uri uri = Uri.parse(ANDROID_RESOURCE + mainActivityPackageName + SLASH + signIdentifier);
if (!isVideoViewDimensionSetToMatchVideoMetadata(this.videoView, uri)) {
return false;
}
this.videoView.setVideoURI(uri);
this.videoView.requestFocus();
this.videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
AbstractSignVideoFragment.this.progressBar.setVisibility(View.GONE);
if (sound.equals(SOUND.OFF)) {
mp.setVolume(0f, 0f);
}
AbstractSignVideoFragment.this.videoView.start();
AbstractSignVideoFragment.this.videoView.setContentDescription(getActivity()
.getString(R.string.videoIsPlaying) + ": " + sign.getName());
Log.d(TAG, String.format("Actual width: %s, Actual height: %s",
AbstractSignVideoFragment.this.videoView.getWidth(),
AbstractSignVideoFragment.this.videoView.getHeight()));
// Set the MediaController to null so the controls are not 'popping up'
// when the video plays for the first time.
AbstractSignVideoFragment.this.videoView.setMediaController(null);
}
});
this.videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
if (controls.equals(CONTROLS.SHOW)) {
initializeMediaController();
}
}
});
return true;
}
private void initializeMediaController() {
final MediaController mediaController = new MediaController(getActivity(), false);
mediaController.setAnchorView(this.videoView);
this.videoView.setMediaController(mediaController);
}
private boolean isVideoViewDimensionSetToMatchVideoMetadata(VideoView videoView, Uri uri) {
String metadataVideoWidth;
String metadataVideoHeight;
try {
final MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
metaRetriever.setDataSource(getActivity(), uri);
metadataVideoWidth = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
metadataVideoHeight = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
metaRetriever.release();
Validate.notEmpty(metadataVideoWidth);
Validate.notEmpty(metadataVideoHeight);
} catch (NullPointerException | IllegalArgumentException ex) {
return false;
}
final double videoWidth = Double.valueOf(metadataVideoWidth);
final double videoHeight = Double.valueOf(metadataVideoHeight);
final double videoRatio = videoWidth/videoHeight;
Log.d(TAG, String.format("videoWidth: %s, videoHeight: %s, videoRatio: %s", videoWidth, videoHeight, videoRatio));
boolean isOrientationPortrait = Configuration.ORIENTATION_PORTRAIT == getResources().getConfiguration().orientation;
int displayHeight = getResources().getDisplayMetrics().heightPixels;
int displayWidth = getResources().getDisplayMetrics().widthPixels;
Log.d(TAG, String.format("displayHeight: %s, displayWidth: %s", displayHeight, displayWidth));
final double desiredVideoWidth, desiredVideoHeight;
if (isOrientationPortrait) {
desiredVideoWidth = displayWidth * MAXIMUM_VIDEO_WIDTH_ON_PORTRAIT;
desiredVideoHeight = 1/(videoRatio/desiredVideoWidth);
Log.d(TAG, String.format("OrientationPortrait: desiredVideoWidth: %s, desiredVideoHeight: %s", desiredVideoWidth, desiredVideoHeight));
} else { // orientation is Landscape
desiredVideoHeight = displayHeight * MAXMIMUM_VIDEO_HEIGHT_ON_LANDSCAPE;
desiredVideoWidth = desiredVideoHeight * videoRatio;
Log.d(TAG, String.format("OrientationLandscape: desiredVideoWidth: %s, desiredVideoHeight: %s", desiredVideoWidth, desiredVideoHeight));
}
final ViewGroup.LayoutParams layoutParams = videoView.getLayoutParams();
layoutParams.width = (int) desiredVideoWidth;
layoutParams.height = (int) desiredVideoHeight;
return true;
}
public enum SOUND {ON, OFF}
public enum CONTROLS {SHOW, HIDE}
}
这里是logcat的输出时,屏幕flickrs哪些循环:
D/v_gal(115): [tid=275] gcmVERIFY_ARGUMENT failed:
D/v_gal(115): [tid=275] gcmONERROR: status=-1(gcvSTATUS_INVALID_ARGUMENT) @ _Blit(2208)
E/v_hwc(115): Failed in _Blit: status=-1
D/v_gal(115): [tid=275] gcmONERROR: status=-1(gcvSTATUS_INVALID_ARGUMENT) @ hwcComposeG2D(615)
E/v_hwc(115): Failed in hwcComposeG2D: status=-1
E/v_hwc(115): _Set(1007): Compose failed
全logcat的输出可以在这里找到:Github issue (full logcat)
视频查看源代码:
< VideoView
android:id="@+id/signTrainerVideoView"
android:layout_width="0dip"
android:layout_height="0dip"
android:layout_below="@+id/signTrainerQuestionText"
android:layout_centerHorizontal="true" />
片段的完整布局XML可以在这里找到:layout xml (full fragment)
严... VideoView是一个非常老的小部件。你有没有尝试过使用TextureView查看这个[link](http://stackoverflow.com/questions/10736517/playing-video-on-textureview) –