layout xml of videoview :
<RelativeLayout
android:id="#+id/videoEditorParent"
android:layout_width="match_parent"
android:layout_height="400dp">
<RelativeLayout
android:id="#+id/vidEditorWrapper"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="#color/colorAccent">
<VideoView
android:id="#+id/vidEditor"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
</RelativeLayout>
when i get height and width of video view it gives me match_parent's width and height, but not aspect ratio width and height of video is playing in videoview(whatever width and height is covered in videoview by video).
here, my code :
viewWidth = vidEditor.getWidth();
viewHeight = vidEditor.getHeight();
ViewGroup.LayoutParams layoutParams = vidEditorWrapper.getLayoutParams();
dpWidthView = utilities.pxToDp(viewWidth);
dpHeightView = utilities.pxToDp(viewHeight);
dpWidthViewPerVal = (dpWidthView * 2) / 100;
layoutParams.width = viewWidth;
layoutParams.height = viewHeight;
vidEditorWrapper.setLayoutParams(layoutParams);
my screen shot :
i want width and height of black area that is video playing in videoview.
but getWidth() or getMeasuredWidth() and getHeight() or getMeasuredHeight() of videoview gives me match_parent width and height.
so, how can i get width and height of video area(only dark area that is visible to us in picture not full width) that is covered in videoview.
Try applying your code inside OnPreparedListener
For eg:
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
viewWidth = vidEditor.getWidth();
viewHeight = vidEditor.getHeight();
ViewGroup.LayoutParams layoutParams =
vidEditorWrapper.getLayoutParams();
dpWidthView = utilities.pxToDp(viewWidth);
dpHeightView = utilities.pxToDp(viewHeight);
dpWidthViewPerVal = (dpWidthView * 2) / 100;
layoutParams.width = viewWidth;
layoutParams.height = viewHeight;
vidEditorWrapper.setLayoutParams(layoutParams);
}
});
Related
I have a VideoView inside a xml which is inside a different xml
<main.xml
<include layout = "#layout/subLayou1"/> >
</main>
<subLayout1.xml
<include layout = "#layout/subLayout2"/> >
</subLayout1>
<subLayout2.xml
<VideoView
android:id="#+id/videoView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:layout_centerInParent="true"
android:background="#android:color/transparent" />
<Button for full screen />
</subLayout2>
but i want this videoview in subLayout2 to take full-screen when a full screen button is clicked.. please help me out!!
In your code you have put the following width height for sublayout
android:layout_width="match_parent"
android:layout_height="match_parent"
Sublayout1 just includes sublayout2. You need to specify certain width and height other than wrap_content and match_parent.
Then in the java file for this activity:
VideoView vv = findViewById(R.id.videoView);
DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics);
android.widget.LinearLayout.LayoutParams params = (android.widget.LinearLayout.LayoutParams) videoView.getLayoutParams();
fullscreenbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
params.width = metrics.widthPixels;
params.height = metrics.heightPixels;
vv.setLayoutParams(params);
}
});
For setting the video back to original:
normalscreenbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
params.width = (int) (original_width_dp*metrics.density);
params.height = (int) (original_height_dp*metrics.density);
vv.setLayoutParams(params);
}
});
During fullscreen you find the value of the screensize and then set it to the videoview. On minimize you have to set the value back to the original. metrics.density converts dp into pixels.
Reference
I am looking for something like the CENTER_CROP in ImageView.ScaleType
Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions (width and height) of the image will be equal to or larger than the corresponding dimension of the view (minus padding). The image is then centered in the view. From XML, use this syntax: android:scaleType="centerCrop"
but for a VideoView. Does anything like this exist?
You can only achieve this with a TextureView. (surfaceView won't work either). Here's a lib for playing video in a textureView with center crop function. TextureView can only be used in api level 14 and up unfortunately.
https://github.com/dmytrodanylyk/android-video-crop
Another possibility is to zoom in the videoview just right, but I haven't tried that yet.
The simple and easy way if you are using ConstraintLayout.
XML
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<VideoView
android:id="#+id/videoView"
android:layout_width="#dimen/dimen_0dp"
android:layout_height="#dimen/dimen_0dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
then
In Kotlin:
videoView.setOnPreparedListener { mediaPlayer ->
val videoRatio = mediaPlayer.videoWidth / mediaPlayer.videoHeight.toFloat()
val screenRatio = videoView.width / videoView.height.toFloat()
val scaleX = videoRatio / screenRatio
if (scaleX >= 1f) {
videoView.scaleX = scaleX
} else {
videoView.scaleY = 1f / scaleX
}
}
See my Java version answer here:
https://stackoverflow.com/a/59069357/6255841
And this worked for me.
Nabin's answer worked for me.
Here is the Java version:
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
float videoRatio = mp.getVideoWidth() / (float) mp.getVideoHeight();
float screenRatio = videoView.getWidth() / (float) videoView.getHeight();
float scaleX = videoRatio / screenRatio;
if (scaleX >= 1f) {
videoView.setScaleX(scaleX);
} else {
videoView.setScaleY(1f / scaleX);
}
}
});
//store the SurfaceTexture to set surface for MediaPlayer
mTextureView.setSurfaceTextureListener(new SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surface,
int width, int height) {
FullScreenActivity.this.mSurface = surface;
}
Just manage overhang of the video out of FrameLayout
<FrameLayout
android:id="#+id/videoViewHolder"
android:layout_width="match_parent"
android:layout_height="200dp"
tools:visibility="visible">
<VideoView
android:id="#+id/videoView"
android:layout_width="match_parent"
android:layout_height="1000dp"
android:layout_gravity="center"/>
</FrameLayout>
I have a RelativeLayout
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:foregroundGravity="center"
android:gravity="center"
android:orientation="horizontal" >
<VideoView
android:id="#+id/videoViewPanel"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:layout_centerInParent="true"/>
</RelativeLayout>
And what I need is to show video fullscreen cropped. If I could compare to ImageView, I need to show it as crop_center.
How can I make VideoView not to auto-resize video to fit center, but crop center?
In Android's VideoView, here is a simple and easy way to achieve the same effect as ImageView.ScaleType.CENTER_CROP
xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<VideoView
android:id="#+id/videoView"
android:layout_width="#dimen/dimen_0dp"
android:layout_height="#dimen/dimen_0dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
In JAVA:
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
float videoRatio = mp.getVideoWidth() / (float) mp.getVideoHeight();
float screenRatio = videoView.getWidth() / (float)
videoView.getHeight();
float scaleX = videoRatio / screenRatio;
if (scaleX >= 1f) {
videoView.setScaleX(scaleX);
} else {
videoView.setScaleY(1f / scaleX);
}
}
});
In Kotlin:
videoView.setOnPreparedListener { mediaPlayer ->
val videoRatio = mediaPlayer.videoWidth / mediaPlayer.videoHeight.toFloat()
val screenRatio = videoView.width / videoView.height.toFloat()
val scaleX = videoRatio / screenRatio
if (scaleX >= 1f) {
videoView.scaleX = scaleX
} else {
videoView.scaleY = 1f / scaleX
}
}
And this worked for me. Hope this will help someone.
The solution is to use TextureView instead of VideoView(SurfaceView).
TextureView does not make any manipulations with the content to fit it ti the screen.
Here is the code sample for the solution:
//store the SurfaceTexture to set surface for MediaPlayer
mTextureView.setSurfaceTextureListener(new SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surface,
int width, int height) {
FullScreenActivity.this.mSurface = surface;
}
....
Surface s = new Surface(mSurface);
mPlayer = mp;
mp.setSurface(s);
scaleVideo(mp);//<-- this function scales video to run cropped
....
private void scaleVideo(MediaPlayer mPlayer) {
LayoutParams videoParams = (LayoutParams) mTextureView
.getLayoutParams();
DisplayMetrics dm = new DisplayMetrics();
FullScreenActivity.this.getWindowManager().getDefaultDisplay()
.getMetrics(dm);
final int height = dm.heightPixels;
final int width = dm.widthPixels;
int videoHeight = mPlayer.getVideoHeight();
int videoWidth = mPlayer.getVideoWidth();
double hRatio = 1;
hRatio = (height * 1.0 / videoHeight) / (width * 1.0 / videoWidth);
videoParams.x = (int) (hRatio <= 1 ? 0 : Math.round((-(hRatio - 1) / 2)
* width));
videoParams.y = (int) (hRatio >= 1 ? 0 : Math
.round((((-1 / hRatio) + 1) / 2) * height));
videoParams.width = width - videoParams.x - videoParams.x;
videoParams.height = height - videoParams.y - videoParams.y;
Log.e(TAG, "x:" + videoParams.x + " y:" + videoParams.y);
mTextureView.setScaleX(1.00001f);//<-- this line enables smoothing of the picture in TextureView.
mTextureView.requestLayout();
mTextureView.invalidate();
}
I just put video inside ConstraintLayout with such parameters. This helped stretch video and achieve android:scaleType="centerCrop" effect.
<VideoView
android:id="#+id/video_view"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_gravity="center_horizontal"
android:layout_width="0dp"
android:layout_height="0dp" />
To crop center in fullscreen you can still use a VideoView. Set the VideoView width and height to match the parent inside a RelativeLayout and adjust it to be bigger than the screen and set his position.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/rootLayout"
tools:context="com.example.Activity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_height="match_parent">
<VideoView
android:id="#+id/video_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:layout_centerVertical="true" />
</RelativeLayout>
</RelativeLayout>
And then in onCreate:
RelativeLayout rootView=(RelativeLayout) findViewById(R.id.rootLayout);
Display display=getWindowManager().getDefaultDisplay();
Point size=new Point();
display.getSize(size);
FrameLayout.LayoutParams rootViewParams = (FrameLayout.LayoutParams) rootView.getLayoutParams();
int videoWidth=864;
int videoHeight=1280;
if ((float)videoWidth/(float)videoHeight<(float)size.x/(float)size.y) {
rootViewParams.width=size.x;
rootViewParams.height=videoHeight*size.x/videoWidth;
rootView.setX(0);
rootView.setY((rootViewParams.height-size.y)/2*-1);
} else {
rootViewParams.width=videoWidth*size.y/videoHeight;
rootViewParams.height=size.y;
rootView.setX((rootViewParams.width-size.x)/2*-1);
rootView.setY(0);
}
rootView.setLayoutParams(rootViewParams);
final VideoView mVideoView=(VideoView)findViewById(R.id.video_view);
mVideoView.setVideoURI(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.splash));
mVideoView.requestFocus();
mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
mVideoView.start();
}
});
I have found a solution: The default behavior is just like fitCenter , so I compute the video ratio(width/height) and screen ratio, and then scale the VideoView to full screen. The result is just like centerCrop .
So I have extended VideoView's onMeasure to scale up the video to fit inside a fullscreen view.
here is how:
public void setVideoAspect(int w,int h){
wVideo=w;
hVideo=h;
onMeasure(w, h);
}
#Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if(wVideo!=0 && hVideo!=0)
setMeasuredDimension(wVideo,hVideo);
}
I call setVideoAspect() with the display metrics (width, hight) of the screen. The problem is that this method stretches the video to fit inside the screen. I want to be able to keep the aspect ratio. (I have 4:3 video and 3:2 screen size.) I used the folowing code to give the retained ratio measurements to the view:
int height = (int) (metrics.widthPixels*3/(float)4);
int width= metrics.widthPixels;
mVideoView.setVideoAspect(width,height);
So this does the job but there is an issue: it gives me a 4:3 video with the width of the screen and scales the height correctly, but it doesn't center the video. (It just crops the bottom part of the video instead of the top and the bottom equally.) I have a relative layout containing the VideoView with the gravity of the VideoView set to center.
Try using a FrameLayout instead. I'm not sure why, but if I use a Linear or Relative in my code it won't center, but FrameLayout does. Here is the XML that fit my video to the screen, preserving the ratio and centering it:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/bg">
<!-- Video player -->
<VideoView
android:id="#+id/surface_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"/>
</FrameLayout>
In order to center the video in the RelativeLayout I added both layout_gravity="center" ad layout_centerInParent="true". It works on my Android 4.3 phone.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<VideoView android:id="#+id/surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_centerInParent="true" />
</RelativeLayout>
Cameron's Answer in a programmatic way(in case someone like me needs it) This code is inside onCreate of an activity in my code( 'this' below refers to the activity)
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
FrameLayout fl = new FrameLayout(this);
fl.setLayoutParams(lp);
VideoView vv = new VideoView(this);
FrameLayout.LayoutParams lp2 = new FrameLayout.LayoutParams(lp);
lp2.gravity = Gravity.CENTER;
vv.setLayoutParams(lp2);
fl.addView(vv);
setContentView(fl);
This works for any video keeping the video's aspect ratio. It positions the video inside the VideoView and performs a Center Crop or a Center Inside just like an ImageView.
I am using a VideoView to cover the whole ConstraintLayout. You can use any other layout probably with match_parent as width and height.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<VideoView
android:id="#+id/videoView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
In onCreate:
Uri uri = //The uri of your video.
VideoView videoView = findViewById(R.id.videoView);
videoView.setVideoURI(uri);
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
//Get your video's width and height
int videoWidth = mp.getVideoWidth();
int videoHeight = mp.getVideoHeight();
//Get VideoView's current width and height
int videoViewWidth = videoView.getWidth();
int videoViewHeight = videoView.getHeight();
float xScale = (float) videoViewWidth / videoWidth;
float yScale = (float) videoViewHeight / videoHeight;
//For Center Crop use the Math.max to calculate the scale
//float scale = Math.max(xScale, yScale);
//For Center Inside use the Math.min scale.
//I prefer Center Inside so I am using Math.min
float scale = Math.min(xScale, yScale);
float scaledWidth = scale * videoWidth;
float scaledHeight = scale * videoHeight;
//Set the new size for the VideoView based on the dimensions of the video
ViewGroup.LayoutParams layoutParams = videoView.getLayoutParams();
layoutParams.width = (int)scaledWidth;
layoutParams.height = (int)scaledHeight;
videoView.setLayoutParams(layoutParams);
}
});
Hope it helps someone!
If you are looking for the same effect as ImageView.ScaleType.CENTER_CROP feature in VideoView then
Here is a simple and easy solution
See my XML and Kotlin version answer here:
https://stackoverflow.com/a/59069292/6255841
In JAVA:
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
float videoRatio = mp.getVideoWidth() / (float) mp.getVideoHeight();
float screenRatio = videoView.getWidth() / (float)
videoView.getHeight();
float scaleX = videoRatio / screenRatio;
if (scaleX >= 1f) {
videoView.setScaleX(scaleX);
} else {
videoView.setScaleY(1f / scale);
}
}
});
I have created a widget that is an extension of SurfaceView (very similar to VideoView) and I am working on a feature to stretch the video fully across the device screen when certain action is taken. I've looked at onMeasure function of VideoView and re-wrote it this way:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mStretchVideo) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} else {
int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
if (mVideoWidth > 0 && mVideoHeight > 0) {
if (mVideoWidth * height > width * mVideoHeight) {
height = width * mVideoHeight / mVideoWidth;
} else if (mVideoWidth * height < width * mVideoHeight) {
width = height * mVideoWidth / mVideoHeight;
}
}
setMeasuredDimension(width, height);
}
}
This seems to work fine if I completely stop the video and start playing again. Now I am trying to force the refresh of this SurfaceView after setting the stretch flag so that the video gets stretched while it is playing, but I couldn't figure out how to force a refresh on SurfaceView. I tried android.view.View.invalidate(), android.view.View.refreshDrawableState() and calling android.view.View.measure(int, int) directly with different combinations but did not get any success. Any ideas?
No need of code to play video in full screen mode
Apply the following layout format over the xml containing the videoview it will for sure will play the video in full screen mode. as it is running mine :) Hope it helps
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<VideoView android:id="#+id/myvideoview"
android:layout_width="fill_parent"
android:layout_alignParentRight="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_height="fill_parent">
</VideoView>
</RelativeLayout>
You can call the measure method of the SurfaceView from the Activity like this:
Display display = getWindowManager().getDefaultDisplay();
int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(display.getWidth(),
MeasureSpec.UNSPECIFIED);
int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(display.getHeight(),
MeasureSpec.UNSPECIFIED);
surfaceView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
Javanator is the correct answer. There is no need for additional code. Make sure your video view looks like this
<VideoView android:id="#+id/myvideoview"
android:layout_width="fill_parent"
android:layout_alignParentRight="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_height="fill_parent">