在TextureView中旋转视频/媒体播放器

10
我正在使用camera2,并在我的缩略图上进行长按后显示照片/视频预览。此外,根据拍摄图片时相机的方向,我会对其进行旋转。例如,如果我拍了一张90度的照片,则我的预览也将旋转90度。
一切都很好,我使用一个自定义容器,在那里我使用onLayout和OnMeasure根据屏幕大小、纵横比和方向创建我的预览。它在照片方面运行良好。当我尝试用视频做同样的事情时,问题出现了,它们只能在0度下工作。
我试图旋转包含我的MediaPlayer的TextureView,但这之后我的onLayout变得混乱,无法找到正确的(l,t,r,b)组合来正确地测量它。
以下是我的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>

这是我的Surface代码:
    @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();
                    }

最后,这是我自定义视图中的onMeasure/OnLayout方法。
      @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);
        }
    }

我一直在查看其他帖子,例如Android MediaRecorder making rotated video,我发现无法旋转textureView,但我不敢相信我可以如此轻松地旋转图像,并且必须在此过程中努力旋转90度的视频。


使用 TextureView#setTransform(Matrix transform) - pskink
@pskink 我已经尝试使用SetTransform矩阵,但什么也没发生。我在测量一切之前尝试过,在调用Surface或选择照片时尝试过。视频没有改变,它与以前完全相同:S - Francisco Durdin Garcia
1
setTransform 很好用,我用过很多次,基本上你的 Matrix 计算方法有误。 - pskink
我们是在讨论 VideoView 还是 TextureView - pskink
2
好的,刚刚找到了Matrix设置的代码:http://pastebin.com/HVr1XyaT - pskink
显示剩余7条评论
1个回答

10

感谢@pskink在我的帖子中的意见。最终我使用了矩阵来旋转视频容器(纹理视图)。Pskink给我的方法如下:

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

终于,它起作用了,并且看起来非常棒。通过这个,我可以根据我的设备屏幕和用于录制视频或拍照的纵横比例,完全动态地旋转和缩放任何视频。


2
我也遇到了同样的问题...你能解释一下如何使用你的方法吗?"mThumbnailContainer"是什么,这个"width"和"height"从哪里来的?谢谢。 - Rafael Lima
为什么这一行代码:src = new RectF(0, 0,mThumbnailContainer.getmWidth(), mThumbnailContainer.getmHeight()); 被else语句重复了呢? - Kirk_hehe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接