I have written a sample app that reproduces the problem:
https://github.com/blundell/VideoRatioProblemPerDevice
The VideoView documentation states:
Displays a video file. ... takes care of computing its measurement from the video so that it can be used in any layout manager, and provides various display options such as scaling
The problem is the Samsung Galaxy S3 is doing weird things to the video and not respecting the ratio of the video. (also happening on an HTC device).
Activity with full screen fragment:
What I have found is when the video is played on the Samsung Galaxy S3 it will play in an incorrect ratio. It looks like it has been stretched to the height of the view without any regard for the ratio of the original video.
here:
However if I play the video on a Samsung Galaxy Nexus the video is in the correct ratio.
here:
If I force the video to take up the full size of the fragment it looks ok on the S3 (because the ratio of the screen is the ratio of the video). However I don't want to do this as it screws up the fragment being used in other places i.e. tablets.
The code is:
An Activity with a Fragment with a VideoView. It can be seen here: GITHUB CODE LINK
if you want some code here is hte VideoPlayerFragment:
public class VideoPlayerFragment extends Fragment {
private static final String TAG = "VideoPlayer";
private FitVideoView videoView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_video_player, container, false);
videoView = (FitVideoView) root.findViewById(R.id.surface);
return root;
}
public void playVideo() {
Uri uri = Uri.parse("android.resource://" + getActivity().getPackageName() + "/" + R.raw.test_vid);
Log.d(TAG, "Uri is: " + uri);
setVideoLocation(uri);
if (!videoView.isPlaying()) {
videoView.start();
}
}
private void setVideoLocation(Uri uri) {
try {
videoView.setVideoURI(uri);
} catch (Exception e) {
Log.e(TAG, "VideoPlayer uri was invalid", e);
Toast.makeText(getActivity(), "Not found", Toast.LENGTH_SHORT).show();
}
}
public void pauseVideo() {
if (videoView.isPlaying()) {
videoView.pause();
}
}
}
So this issue occurs with VideoView
and with MediaPlayer
+ SurfaceView
.
When the system asks the video for it's width x height it is returning 640x480 when it should be returning 852x480.
i.e.
@Override
public void onPrepared(MediaPlayer mp) {
mp.getVideoWidth();
mp.getVideoHeight();
}
This is either a bug in the MediaPlayer
handling of the video container/codec or an issue with the video file itself.
Either way I have circumvented it by adding what I know the video's width and height is to my code. I have updated the Git Repo with this fix. hack alert
Here's a link to the question where I found out the different size details of my video.
You can apply this fix to the VideoView
or directly to MediaPlayer
+ SurfaceView
your choice. Here's the VideoView
answer:
public class FitVideoView extends VideoView {
private final int mVideoWidth = 853;
private final int mVideoHeight = 480;
private boolean applyFix = true;
public FitVideoView(Context context) {
super(context);
}
public FitVideoView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FitVideoView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (applyFix) { // A Toggle so I can see both results
// This doesn't ask the video for it's size, but uses my hardcoded size
applyFix(widthMeasureSpec, heightMeasureSpec);
} else {
// This asks the video for its size (which gives an incorrect WxH) then does the same code as below
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
private void applyFix(int widthMeasureSpec, int heightMeasureSpec) {
int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
if (mVideoWidth > 0 && mVideoHeight > 0) {
if (mVideoWidth * height > width * mVideoHeight) {
Log.d("TAG", "image too tall, correcting");
height = width * mVideoHeight / mVideoWidth;
} else if (mVideoWidth * height < width * mVideoHeight) {
Log.d("TAG", "image too wide, correcting");
width = height * mVideoWidth / mVideoHeight;
} else {
Log.d("TAG", "aspect ratio is correct: " + width + "/" + height + "=" + mVideoWidth + "/" + mVideoHeight);
}
}
Log.d("TAG", "setting size: " + width + 'x' + height);
setMeasuredDimension(width, height);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With