Rotate Video / MediaPlayer in TextureView

Im working with camera2 and im showing a preview of my photo / video after longclick in my thumbnail. In addition, im rotates it depending on what orientation the camera had when the image was captured. For example, if I took a picture at 90º, my view would also be rotated 90º.

Everything works fine, I use customContainer, and there I use onLayout and OnMeasure to create my preview depending on the screen size, aspect ratio and orientation. It works great with photos. My problem arises when I try to do the same with videos, they only work at 0º.

I tried to rotate the TextureView that my MediaPlayer contains, but after that my onLayout gets crazy and it is impossible to find the combination (l, t, r, b) 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 trying to fix this in recent days, but I have no way to fix it, I looked in another post as Android MediaRecorder making a rotary video , and I saw that it is impossible to rotate the texture, but I cannot believe that I can do this easily rotate the image and must fight during this to rotate the video 90 degrees.

Hope someone can find a solution! Have a good day!

+4
1

@pskink . , ( ). , pskink , :

  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, cause 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);
}

, , . , .

Pskink , , , . , , , , .

, !

+5

All Articles