I'm working with camera2 and I'm showing a preview of my photo/video after longclick in my thumbnail. Also, I'm rotating it depending of which orientation the camera had when the picture was taken. For example, if I did a picture in 90º, my preview will be also rotated 90º.
Everything is working fine, I'm using a customContainer and there I'm using onLayout and OnMeasure to create my preview depending of the size of the screen, aspect ratio and orientation. It works fine with photos. My problem appear when I try to do the same with videos, they only work in 0º.
I tried to rotate the TextureView which contain my MediaPlayer but after this my onLayout become crazy and Itś impossible find a (l,t,r,b) combination to measure it correctly.
Here is my XML:
<?xml version="1.0" encoding="utf-8"?>
<com.android.camera.ui.common.ThumbnailContainer xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/preview_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/rounded_rectangle_thumbnail_preview"
android:visibility="invisible">
<TextureView
android:id="@+id/show_video_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible"/>
<ImageView
android:id="@+id/image_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:visibility="invisible"
/>
</com.android.camera.ui.common.ThumbnailContainer>
Here is my Surface code:
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Log.i(TAG, "InicializoSurface. Width: " + width + " HEIGHT:" + height);
Log.i(TAG, "InicializoSurface. Width: " + mVideoView.getMeasuredWidth() + " HEIGHT:" + mVideoView.getMeasuredHeight());
Log.i(TAG, "View transform. Width: " + mVideoView.getWidth() + " HEIGHT:" + mVideoView.getHeight());
mMediaSurface = new Surface(mVideoView.getSurfaceTexture());
initializeMediaPlayer();
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
if (mMediaPlayer != null) {
// Make sure we stop video and release resources when activity is destroyed.
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
}
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
//////////
private void initializeMediaPlayer(){
mMediaPlayer = new CustomMediaPlayer();
Uri uri = Uri.parse(mCameraDataAdapter.getList().get(0).getPath());
try {
mMediaPlayer.setDataSource(mActivity, uri);
mMediaPlayer.setSurface(mMediaSurface);
mMediaPlayer.prepareAsync();
mMediaPlayer.setOnPreparedListener(mMediaPlayer);
mMediaPlayer.setOnCompletionListener(mMediaPlayer);
} catch (IOException e) {
e.printStackTrace();
}
}
///////////
mVideoView.setVisibility(View.VISIBLE);
// mVideoView.setTranslationX(-200);
// mVideoView.setTranslationY(-200);
Log.i(TAG, "X: " + mVideoView.getX() + "Y: " + mVideoView.getY());
if (mVideoView.isAvailable()) {
onSurfaceTextureAvailable(mVideoView.getSurfaceTexture(), mVideoView.getWidth(), mVideoView.getHeight());
}
if (mMediaPlayer == null) {
initializeMediaPlayer();
}
// mMediaPlayer.mVideoHolder = mVideoView.getHolder();
// mMediaPlayer.setDisplay(mMediaPlayer.mVideoHolder);
if (mMediaPrepared) {
Log.i(TAG,"Comienzo Video");
mMediaPlayer.start();
}
Finally here is my onMeasure/OnLayout from my CustomView
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width;
int height;
int wantedWidth = 0;
int wantedHeight = 0;
if(mWidth == 0 && mHeight == 0 ){
mWidth = MeasureSpec.getSize(widthMeasureSpec);
mHeight =MeasureSpec.getSize(heightMeasureSpec);
}
width = mWidth;
height = mHeight;
if (mOrientation == 0 || mOrientation == 180) {
wantedWidth = width - (int)(mMargin * 2);
mVideo.measure(MeasureSpec.makeMeasureSpec(wantedWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((int) (wantedWidth * mVideoAspectRatio), MeasureSpec.EXACTLY));
wantedHeight = (mViewTop.getLayoutParams().height) * 2 + (int) (wantedWidth * mAspectRatio);
} else {
Log.e(TAG, "Real Width = " + width + " real Height = " + height);
wantedHeight = width - 2 * mViewTop.getLayoutParams().height - (int)(mMargin * 2);
mVideo.measure(MeasureSpec.makeMeasureSpec(wantedHeight, MeasureSpec.EXACTLY),MeasureSpec.makeMeasureSpec((int) (wantedHeight * mAspectRatio), MeasureSpec.EXACTLY));
//
wantedWidth =(int) (wantedHeight * mAspectRatio) ;
wantedHeight = width - (int)(mMargin * 2);
}
Log.e(TAG, "onMeasure: " + wantedWidth + "x" + wantedHeight);
setMeasuredDimension(MeasureSpec.makeMeasureSpec(wantedWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(wantedHeight, MeasureSpec.EXACTLY));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int w = getMeasuredWidth();
int h = getMeasuredHeight();
int viewHeight = mViewBottom.getMeasuredHeight();
int imageViewHeight = mImage.getMeasuredHeight();
int wantedHeight = 0;
// w = w - (int) (2 * mMargin);
if (mOrientation == 0 || mOrientation == 180) {
mVideo.layout(0,wantedHeight,w,wantedHeight + imageViewHeight);
}else{
mVideo.layout(viewHeight,0,r-viewHeight - (int) mMargin,w);
}
}
I have been looking in other post as Android MediaRecorder making rotated video and I saw that it's not possible to rotate the textureView, but I can't believe that I can rotate a image so easily and have to fight during this to rotate 90 degrees a video.
Thanks to @pskink for their comments in the post I found a solution with him. Finally I used a Matrix to rotate the Video Container(Texture View). The method that pskink give me is the next one:
private void setupMatrix(int width, int height, int degrees, boolean isHorizontal) {
Log.d(TAG, "setupMatrix for " + degrees + " degrees");
Matrix matrix = new Matrix();
//The video will be streched if the aspect ratio is in 1,5(recording at 480)
RectF src;
if (isHorizontal)
//In my case, I changed this line, because with my onMeasure() and onLayout() methods my container view is already rotated and scaled, so I need to sent the inverted params to the src.
src = new RectF(0, 0,mThumbnailContainer.getmWidth(), mThumbnailContainer.getmHeight());
else
src = new RectF(0, 0, mThumbnailContainer.getmWidth(),mThumbnailContainer.getmHeight());
RectF dst = new RectF(0, 0, width, height);
RectF screen = new RectF(dst);
Log.d(TAG, "Matrix: " + width + "x" + height);
Log.d(TAG, "Matrix: " + mThumbnailContainer.getmWidth() + "x" + mThumbnailContainer.getmHeight());
matrix.postRotate(degrees, screen.centerX(), screen.centerY());
matrix.mapRect(dst);
matrix.setRectToRect(src, dst, Matrix.ScaleToFit.CENTER);
matrix.mapRect(src);
matrix.setRectToRect(screen, src, Matrix.ScaleToFit.FILL);
matrix.postRotate(degrees, screen.centerX(), screen.centerY());
mVideoView.setTransform(matrix);
}
Finally it worked and it looks totally awesome. With this I have been able to rotate and scale any video totally dynamically depending of the screen of my device and the Aspect Ratio used for record the video or take the picture.
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