TextureVideo, media player and aspect ratio - android

I have a TextureView in which a video is showing, a video previously recorded with device camera. The image in the video is stretched, and that is not acceptable. I did some research, and found this method:
private void adjustAspectRatio(int videoWidth, int videoHeight) {
int viewWidth = m_TextureView.getWidth();
int viewHeight = m_TextureView.getHeight();
double aspectRatio = (double) videoHeight / videoWidth;
int newWidth, newHeight;
if (viewHeight > (int) (viewWidth * aspectRatio)) {
// limited by narrow width; restrict height
newWidth = viewWidth;
newHeight = (int) (viewWidth * aspectRatio);
} else {
// limited by short height; restrict width
newWidth = (int) (viewHeight / aspectRatio);
newHeight = viewHeight;
}
int xoff = (viewWidth - newWidth) / 2;
int yoff = (viewHeight - newHeight) / 2;
Log.v(TAG, "video=" + videoWidth + "x" + videoHeight +
" view=" + viewWidth + "x" + viewHeight +
" newView=" + newWidth + "x" + newHeight +
" off=" + xoff + "," + yoff);
Matrix txform = new Matrix();
m_TextureView.getTransform(txform);
txform.setScale((float) newWidth / viewWidth, (float) newHeight / viewHeight);
//txform.postRotate(10); // just for fun
txform.postTranslate(xoff, yoff);
m_TextureView.setTransform(txform);
}
Tried to use it, but I see a black background only.
This is mu onSurfaceTextureAvailable, in case it helps:
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
isVideoResultReady=true;
Surface s=new Surface(surface);
if(mPlayer==null){
mPlayer=new MediaPlayer();
}
try {
//mPlayer.setDataSource(videoPath);
mPlayer.setSurface(s);
mPlayer.prepare();
mPlayer.setOnBufferingUpdateListener(this);
mPlayer.setOnCompletionListener(this);
mPlayer.setOnPreparedListener(this);
//media player is started in other point of the app
} catch (IOException e) {
e.printStackTrace();
}
}
What is wrong with that method? How to keep aspect ratio? Thanks.

Related

How resize TextureView to fullscreen when rotation 90?

I using a TextureView to play video:
I have to use rotation=90 to display video correct orientation when record video
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#777777" >
<TextureView
android:id="#+id/textureView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:rotation="90"
android:layout_alignParentTop="true" />
i try set setTransform of TextureView to resize video to fullsreen, but it not working:
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
Surface surface = new Surface(surfaceTexture);
try {
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setDataSource(FILE_NAME);
mMediaPlayer.setSurface(surface);
mMediaPlayer.setLooping(false);
mMediaPlayer.prepareAsync();
updateTextureViewScaling(width,height);
// Play video when the media source is ready for playback.
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
}
});
} catch (IllegalArgumentException e) {
Log.d(TAG, e.getMessage());
} catch (SecurityException e) {
Log.d(TAG, e.getMessage());
} catch (IllegalStateException e) {
Log.d(TAG, e.getMessage());
} catch (IOException e) {
Log.d(TAG, e.getMessage());
}
}
private void updateTextureViewScaling(int viewWidth, int viewHeight) {
float scaleX = 1.0f;
float scaleY = 1.0f;
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int VIDEO_HEIGHT = displayMetrics.heightPixels;
int VIDEO_WIDTH = displayMetrics.widthPixels;
if (VIDEO_WIDTH > viewWidth && VIDEO_WIDTH > viewHeight) {
scaleX = (float) VIDEO_WIDTH / viewWidth;
scaleY = (float) VIDEO_HEIGHT / viewHeight;
} else if (VIDEO_WIDTH < viewWidth && VIDEO_HEIGHT < viewHeight) {
scaleY = (float) viewWidth / VIDEO_WIDTH;
scaleX = (float) viewHeight / VIDEO_HEIGHT;
} else if (viewWidth > VIDEO_WIDTH) {
scaleY = ((float) viewWidth / VIDEO_WIDTH) / ((float) viewHeight / VIDEO_HEIGHT);
} else if (viewHeight > VIDEO_HEIGHT) {
scaleX = ((float) viewHeight / VIDEO_WIDTH) / ((float) viewWidth / VIDEO_WIDTH);
}
// Calculate pivot points, in our case crop from center
int pivotPointX = viewWidth / 2;
int pivotPointY = viewHeight / 2;
Matrix matrix = new Matrix();
matrix.setScale(scaleX, scaleY, pivotPointX, pivotPointY);
textureView.setTransform(matrix);
}
Target result:
Image 1: not set android:rotation="90"
Image 2: set android:rotation="90"
How can set width and height of video to fullscreen:
i had log:
Width and Height in onSurfaceTextureAvailable = size of Screen.
My problem had fixed by:
put TextureView in a FrameLayout
and update function updateTextureViewScaling
private void updateTextureViewScaling(int viewWidth, int viewHeight) {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) textureView.getLayoutParams();
params.width = viewHeight;
params.height =viewWidth;
params.gravity= Gravity.CENTER;
textureView.setLayoutParams(params);
}
Overide this method in Activity:
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
textview.setRotation(90);
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
textview.setRotation(0);
}
}
in Android Manifest file mention this under activity
android:configChanges="orientation|screenSize".

Camera PreviewView is stretched in some Android devices

I'm playing with the API2 Camera of Google and I'm having some problems with my code. I had two different CameraSessions, one for video and another one for images. To do it more efficient I change the code to use a unique Session and make the app more efficient.
After I did this, my camera preview is not working adequately. When I'm using a 4:3 aspect ratio my preview become stretched at height. In other way it looks fine when I'm using 16:9 ratio. In both cases my pictures looks fine, I mean, preview doesn't work correctly but the pictures that I took, have the correct aspect ratio.
I already check different post with the same problem:
Camera Preview Stretched on Few Android Devices
Camera display / preview in full screen does not maintain aspect ratio - image is skewed, stretched in order to fit on the screen
But the different answers didn't help me. I know that the problem is inside my onMeasure(), setTransformMatrix() or OnLayoutChangeListener() methods, but I don't know what I'm doing wrong.
Ignore the code about Rotation, right now it's dynamic. It always enter at else condition.
Here is my code:
private OnLayoutChangeListener mLayoutListener = new OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right,
int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
Log.d(TAG, "[onLayoutChange] " + mCameraUI.getTextureView().getMeasuredWidth() + "x" + mCameraUI.getTextureView().getMeasuredHeight());
int width = right - left;
int height = bottom - top;
if (mPreviewWidth != width || mPreviewHeight != height
|| (mOrientationResize != mPrevOrientationResize)
|| mAspectRatioResize || mOrientationChanged) {
Log.i(TAG, "[onLayoutChange] Layout changed");
mPreviewWidth = width;
mPreviewHeight = height;
Log.i(TAG, "[onLayoutChange] Preview size: "+ mPreviewWidth + "x" + mPreviewHeight);
setTransformMatrix(width, height);
mController.onScreenSizeChanged((int) mSurfaceTextureUncroppedWidth,
(int) mSurfaceTextureUncroppedHeight);
mAspectRatioResize = false;
mOrientationChanged = true;
}
}
};
setTransform
private void setTransformMatrix(int width, int height) {
Log.i(TAG, "Screen: " + mPreviewWidth + "x" + mPreviewHeight);
mMatrix = new Matrix();
//mCameraUI.getTextureView().getTransform(mMatrix);
float scaleX = 1f, scaleY = 1f;
float scaledTextureWidth, scaledTextureHeight;
mAspectRatio= (float)height/(float)width;
if (mAspectRatio==(4f / 3f)){
scaledTextureWidth = Math.max(width,
(int) (height / mAspectRatio));
scaledTextureHeight = Math.max(height,
(int) (width * mAspectRatio));
Log.i(TAG, "[PhotoUIManager]: Aspect Ratio 4:3=" + scaledTextureWidth + "x" + scaledTextureHeight );
}
else{
scaledTextureWidth = Math.max(width,
(int) (height / mAspectRatio));
scaledTextureHeight = Math.max(height,
(int) (width * mAspectRatio));
Log.i(TAG, "[PhotoUIManager]: Aspect Ratio 16:9=" + scaledTextureWidth + "x" + scaledTextureHeight );
}
if (mSurfaceTextureUncroppedWidth != scaledTextureWidth || mSurfaceTextureUncroppedHeight != scaledTextureHeight) {
Log.e(TAG,"mi SurfaceWidth = " + mSurfaceTextureUncroppedWidth + "and mi scaledWidth=" + scaledTextureWidth);
Log.e(TAG,"mi SurfaceHeigh = " + mSurfaceTextureUncroppedHeight + "and mi scaledHeight=" + scaledTextureHeight);
mSurfaceTextureUncroppedWidth = scaledTextureWidth;
mSurfaceTextureUncroppedHeight = scaledTextureHeight;
Log.e(TAG,"Surfaces: " + mSurfaceTextureUncroppedWidth + "x" + mSurfaceTextureUncroppedHeight);
if (mSurfaceTextureSizeListener != null) {
mSurfaceTextureSizeListener.onSurfaceTextureSizeChanged(
(int) mSurfaceTextureUncroppedWidth, (int) mSurfaceTextureUncroppedHeight);
}
}
scaleX = scaledTextureWidth / width;
scaleY = scaledTextureHeight / height;
mMatrix.setScale(scaleX, scaleY, scaledTextureWidth/2, scaledTextureHeight/2);
Log.e(TAG, "scale: X= " + scaleX + " Y=" + scaleY + "Width= " + scaledTextureWidth + "Height= " + scaledTextureHeight);
// init the position (this seems to be necessary too when the ratio is 16/9
mCameraUI.getTextureView().setX(0);
mCameraUI.getTextureView().setY(0);
// Translate the preview with the rotation is aspect ration is 4/3
if (mAspectRatio == 4f / 3f) {
Log.e(TAG, "aspect ratio standard");
float verticalTranslateOffset = (mCameraUI.getTextureView().getMeasuredHeight() - scaledTextureHeight) / 2;
float horizontalTranslateOffset = (mCameraUI.getTextureView().getMeasuredWidth() - scaledTextureWidth) / 2;
int rotation = CameraUtil.getDisplayRotation(mActivity);
switch (rotation) {
case 0:
// phone portrait; translate the preview up
mCameraUI.getTextureView().setY(-verticalTranslateOffset);
mFaceView.setStandardPreviewTranslationOffset(-verticalTranslateOffset);
mFocusView.setStandardPreviewTranslationOffset(-verticalTranslateOffset);
break;
case 90:
// phone landscape: translate the preview left
mCameraUI.getTextureView().setX(-horizontalTranslateOffset);
mFaceView.setStandardPreviewTranslationOffset(-horizontalTranslateOffset);
mFocusView.setStandardPreviewTranslationOffset(-horizontalTranslateOffset);
break;
case 180:
// phone upside down: translate the preview bottom
mCameraUI.getTextureView().setY(verticalTranslateOffset);
mFaceView.setStandardPreviewTranslationOffset(verticalTranslateOffset);
mFocusView.setStandardPreviewTranslationOffset(verticalTranslateOffset);
break;
case 270:
// reverse landscape: translate the preview right
mCameraUI.getTextureView().setX(horizontalTranslateOffset);
mFaceView.setStandardPreviewTranslationOffset(horizontalTranslateOffset);
mFocusView.setStandardPreviewTranslationOffset(horizontalTranslateOffset);
break;
}
} else {
Log.e(TAG, "aspect ratio full");
mFaceView.setStandardPreviewTranslationOffset(0);
mFocusView.setStandardPreviewTranslationOffset(0);
}
mRenderOverlay.updateLayout();
mCameraUI.getTextureView().setTransform(mMatrix);
RectF previewRect = new RectF(0, 0, width, height);
mController.onPreviewRectChanged(CameraUtil.rectFToRect(previewRect));
}
onMeasure
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
Log.d(TAG, "onMeasure PREVIOUS. Width x Height [" + widthMeasureSpec + " = " + width + "x" + heightMeasureSpec + " = " + height + "]");
int rotation = ((Activity) getContext()).getWindowManager().getDefaultDisplay().getRotation();
boolean isInHorizontal = Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation;
int newWidth;
int newHeight;
if (isInHorizontal) {
newHeight = getMeasuredHeight();
newWidth = (int) (newHeight * mAspectRatio);
} else {
newWidth = getMeasuredWidth();
newHeight = (int) (newWidth * mAspectRatio);
}
setMeasuredDimension(newWidth, newHeight);
Log.d(TAG, "onMeasure. Width x Height [" + newWidth + "x" + newHeight + "]");
}
Solved!
I had a default values for the BufferSize of my texture, which just are restarted when I inicializated a new Session or after change the after ratio. But the Width and Height values for the texture were not updated with the ratio, so it becomes streched again and again.
I solved it changing my defaultbufferSize with the PreviewSizes which I update always that i change the ratio.
public void createCameraPreviewSession(Size previewsize, Surface recordingSurface) {
try {
if (mCaptureSession != null) {
mCaptureSession.stopRepeating();
mCaptureSession.close();
mCaptureSession = null;
}
SurfaceTexture texture = mTextureView.getSurfaceTexture();
assert texture != null;
List<Surface> surfaces = new ArrayList<Surface>();
// We configure the size of default buffer to be the size of camera preview we want.
texture.setDefaultBufferSize(previewsize.getWidth(),previewsize.getHeight());
;
// This is the output Surface we need to start preview.
Surface surface = new Surface(texture);
.......

Resizing a view while it is rotated in Android

I am working on a sample application which allows resizing of view on dragging
the selection knobs. Resizing works fine when the view is not rotated. When the
view is rotated, if we resize the view, it gets offset by a certain amount. I
need to make the opposite corner of the view stay in its original position
while the view is being resized. Could anyone help me in understanding how this can
be achieved in android. The code snippet for resize is given below:
public void resize(float dx, float dy, SelectionView.KnobTypes selectedKnob) {
float newDx = dx;
float newDy = dy;
FrameLayout.LayoutParams params;
float viewWidth, viewHeight, ratio, newWidth, newHeight;
viewWidth = getWidth();
viewHeight = getHeight();
ratio = 1;
switch (selectedKnob) {
case eLeftTop:
newWidth = viewWidth - dx;
newHeight = viewHeight - dy;
if (newWidth <= mKnobRadius * 4 || newHeight <= mKnobRadius * 4) {
break;
}
if (viewWidth > viewHeight) {
if (viewHeight != 0) {
ratio = viewWidth / viewHeight;
}
newWidth = newHeight * ratio;
} else {
if (viewWidth != 0) {
ratio = viewHeight / viewWidth;
}
newHeight = newWidth * ratio;
}
params = new FrameLayout.LayoutParams(Math.round(newWidth),
Math.round(newHeight));
setLayoutParams(params);
newDx = Math.round(newWidth) - Math.round(viewWidth);
newDy = Math.round(newHeight) - Math.round(viewHeight);
setTranslationX(getTranslationX() - newDx);
setTranslationY(getTranslationY() - newDy);
break;
case eTopRight:
newWidth = viewWidth + dx;
newHeight = viewHeight - dy;
if (newWidth <= mKnobRadius * 4 || newHeight <= mKnobRadius * 4) {
break;
}
if (viewWidth > viewHeight) {
if (viewHeight != 0) {
ratio = viewWidth / viewHeight;
}
newWidth = newHeight * ratio;
} else {
if (viewWidth != 0) {
ratio = viewHeight / viewWidth;
}
newHeight = newWidth * ratio;
}
params = new FrameLayout.LayoutParams(Math.round(newWidth),
Math.round(newHeight));
setLayoutParams(params);
newDx = Math.round(newWidth) - Math.round(viewWidth);
newDy = Math.round(newHeight) - Math.round(viewHeight);
setTranslationY(getTranslationY() - newDy);
break;
case eRightBottom:
newWidth = viewWidth + dx;
newHeight = viewHeight + dy;
if (newWidth <= mKnobRadius * 4 || newHeight <= mKnobRadius * 4) {
break;
}
if (viewWidth > viewHeight) {
if (viewHeight != 0) {
ratio = viewWidth / viewHeight;
}
newWidth = newHeight * ratio;
} else {
if (viewWidth != 0) {
ratio = viewHeight / viewWidth;
}
newHeight = newWidth * ratio;
}
params = new FrameLayout.LayoutParams(Math.round(newWidth),
Math.round(newHeight));
setLayoutParams(params);
break;
case eLeftBottom:
newWidth = viewWidth - dx;
newHeight = viewHeight + dy;
if (newWidth <= mKnobRadius * 4 || newHeight <= mKnobRadius * 4) {
break;
}
if (viewWidth > viewHeight) {
if (viewHeight != 0) {
ratio = viewWidth / viewHeight;
}
newWidth = newHeight * ratio;
} else {
if (viewWidth != 0) {
ratio = viewHeight / viewWidth;
}
newHeight = newWidth * ratio;
}
params = new FrameLayout.LayoutParams(Math.round(newWidth),
Math.round(newHeight));
setLayoutParams(params);
newDx = Math.round(newWidth) - Math.round(viewWidth);
newDy = Math.round(newHeight) - Math.round(viewHeight);
setTranslationX(getTranslationX() - newDx);
break;
default:
break;
}
}
dx and dy are the offset by which the mouse is moved, selected knob is the knob which is currently being dragged.
The working sample is uploaded to this github repo:
https://github.com/vivekrk/resizesample.git

Issue when playing video in local and url path

I play the video in VideoView
When I play from SD Card, it shows correct width and height in full screen. When I try to play from server, video Width is smaller and the video is re-sized.
How can I play the video in original size and full screen?
Take a look at the documentation and implement the onPrepared method like the following code:
//prepare the video
public void onPrepared(MediaPlayer mp) {
progressBarWait.setVisibility(View.GONE);
//First get the size of the video
int videoWidth = player.getVideoWidth();
int videoHeight = player.getVideoHeight();
float videoProportion = (float) videoWidth / (float) videoHeight;
//get the size of the screen
int screenWidth = getWindowManager().getDefaultDisplay().getWidth();
int screenHeight = getWindowManager().getDefaultDisplay().getHeight();
float screenProportion = (float) screenWidth / (float) screenHeight;
//Adjust
LayoutParams lp = surfaceViewFrame.getLayoutParams();
if (videoProportion > screenProportion) {
lp.width = screenWidth;
lp.height = (int) ((float) screenWidth / videoProportion);
} else {
lp.width = (int) (videoProportion * (float) screenHeight);
lp.height = screenHeight;
}
surfaceViewFrame.setLayoutParams(lp);
if (!player.isPlaying()) {
player.start();
}
surfaceViewFrame.setClickable(true);
}

Pass drawable image to TypedArray in Android

I am trying to implement a segmentated radio button from here: https://github.com/makeramen/android-segmentedradiobutton but I need to set the image programmatically and not in XML.
This is the source of the custom RadioButton:
public class CenteredImageButton extends RadioButton {
Drawable image;
public CenteredImageButton(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.CompoundButton, 0, 0);
image = a.getDrawable(1);
setButtonDrawable(android.R.id.empty);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (image != null) {
image.setState(getDrawableState());
// scale image to fit inside button
int imgHeight = image.getIntrinsicHeight();
Log.d("IMAGEHEIGHT", "imageWidth is " + imgHeight);
int imgWidth = image.getIntrinsicWidth();
Log.d("IMAGEWIDTH", "imageWidth is " + imgWidth);
int btnWidth = getWidth();
Log.d("BUTTONWIDTH", "buttonWidth is " + btnWidth);
int btnHeight = getHeight();
Log.d("BUTTONHEIGHT", "buttonHeight is " + btnHeight);
float scale;
if (imgWidth <= btnWidth && imgHeight <= btnHeight) {
scale = 1.0f;
} else {
scale = Math.min((float) btnWidth / (float) imgWidth,
(float) btnHeight / (float) imgHeight);
}
Log.d("SCALE", "scale is " + scale);
int dx = (int) ((btnWidth - imgWidth * scale) * 0.5f + 0.5f);
Log.d("DX", "dx is " + dx);
int dy = (int) ((btnHeight - imgHeight * scale) * 0.5f + 0.5f);
Log.d("DY", "dy is " + dy);
image.setBounds(dx, dy, (int) (dx + imgWidth * scale),
(int) (dy + imgHeight * scale));
image.draw(canvas);
}
}
I am setting the drawable in another file like this:
private void setButtonImageProperties(RadioButton button,Drawable drawable){
button.setGravity(Gravity.CENTER);
Resources resources = this.context.getResources();
float dipValue = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
60, resources.getDisplayMetrics());
float dipValue1 = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 80, resources.getDisplayMetrics());
button.setMinHeight((int) dipValue);
button.setMinWidth((int) dipValue1);
button.setButtonDrawable(drawable);
}
Please anyone, advise. I really need helping hand. Thanks.
You pretty much need to add a setImage method to CenteredImageButton:
public void setImage(Drawable newImage) {
image = newImage;
}
And just call it later in your main code:
button.setImage(drawable);
See this Gist to see the method inline: https://gist.github.com/1470789
I also noticed you changed the name of my class from CenteredRadioImageButton to CenteredImageButton. If you're not actually using this for the RadioButton-like behavior, I would suggest using a standard ImageButton
(I am the maintainer of SegmentedRadioButton)

Categories

Resources