10

I'm facing a strange issue with the Android MediaPlayer class. I'm using the MediaPlayer to play a video in a VideoView. This works well on all devices, except on an Samsung GT-I8200N with Android 4.2.2. Well, I've actually heard reports that the videos won't play on certain Samsung 4.1.X devices, but I wasn't able to get may hands onto one of these devices. I don't get any errors in the Google Android Emulators.

Some more detail: The Samsung GT-I8200N with Android 4.2.2 is able to play the videos in one fragment, but not in another, even though the same code is used to play the videos. When the video is starting the whole screen flickrs black, except at the space where the video should be.

Here is the code:

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}
}

Here is the logcat output which loops when the screen 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


The full logcat output can be found here: Github issue (full logcat)

Video view code :

< VideoView
android:id="@+id/signTrainerVideoView"
android:layout_width="0dip"
android:layout_height="0dip"
android:layout_below="@+id/signTrainerQuestionText"
android:layout_centerHorizontal="true" />


The full layout xml of the fragment can be found here: layout xml (full fragment)

Matthias T
  • 1,230
  • 2
  • 10
  • 24

1 Answers1

0

I'm unsure of if this will solve the problem, but I'll just report what seems improvable in there.

In order to actualize your VideoView size :

final ViewGroup.LayoutParams layoutParams = videoView.getLayoutParams();
layoutParams.width = (int) desiredVideoWidth;
layoutParams.height = (int) desiredVideoHeight;
videoView.setLayoutParams(layoutParams); // Input Changes
videoView.getHolder().setSizeFromLayout(); // Apply Changes

Plus from what I experimented, "0dip" size implies computing with the weight parameter, which you doesn't seems to provides. Might be wrong but worth mentioning.

// Add android:weightSum="1" to the sup. Layout
// And set a weight there
<VideoView
            android:id="@+id/signTrainerVideoView"
            android:layout_width="0dip"
            android:layout_height="0dip"
            android:layout_weight="1"
            android:layout_below="@+id/signTrainerQuestionText"
            android:layout_centerHorizontal="true" />
J.Jacobs
  • 703
  • 6
  • 17