android視頻適配與裁剪

首先說下基本背景, 當咱們使用android系統原生的VideoView播放視頻時, 在XML中給它設置的一個尺寸, 但最終視頻開始播放後, VideoView實際的尺寸可能並非這個尺寸設置的大小. VideoView在測量自身的尺寸時會依據視頻的真實尺寸來調整本身的大小, 遵循如下規則: java

1. 實際視頻在VideoView上播放時全部部分都是可見的,或縮小或放大, 總之必定要所有顯示出來,不會裁剪實際視頻. android

2. 儘可能保持實際視頻的長寬比例, 具體是首先以咱們用戶定義的長度爲標準, 等比例縮放視頻大小, 直到長度達到咱們定義的長度, 而後寬度(等比例縮放後的寬度)與咱們定義的寬比較, 大於則以咱們定義的寬度爲準, 這樣視頻會在豎直方向上壓縮, 最終播放時也就不會成比例了; 小於則它以視頻縮放後的寬度爲準, 這樣它會比咱們定義的高度小,最終播放的效果是等比例的. git

最近開發有以下需求: github

視頻等比例放大,直至一邊鋪滿VideoView(或屏幕)的某一邊,另外一邊超出View的另外一邊,再移動到View的正中央,這樣長邊兩邊會被裁剪掉一樣大小的區域,視頻看起來不會變形,也便是:先把視頻區(實際的大小顯示區)與View(定義的大小)區的兩個中心點重合, 而後等比例放大或縮小視頻區,直至一條邊與View的一條邊相等,另外一條邊超過View的另外一條邊,這時再裁剪掉超出的邊, 使視頻區與View區大小同樣. 這樣在不一樣尺寸的手機上,視頻看起來不會變形,只是水平或豎直方向的兩端被裁剪了一些. ide

以上需求用系統的VideoView是沒法達到的,因此要自定義VideoView. post

最終咱們擴展TextureView來自定義一個TextureVideoView, 並應用Matrix進行縮放, 也便是要求出變換的Matrix, 主要按如下步驟來便可求出變換矩陣, 這裏直接貼出代碼: this


//需求:視頻等比例放大,直至一邊鋪滿View的某一邊,另外一邊超出View的另外一邊,再移動到View的正中央,這樣長邊兩邊會被裁剪掉一樣大小的區域,視頻看起來不會變形
    //也便是:先把視頻區(實際的大小顯示區)與View(定義的大小)區的兩個中心點重合, 而後等比例放大或縮小視頻區,直至一條邊與View的一條邊相等,另外一條邊超過
    //View的另外一條邊,這時再裁剪掉超出的邊, 使視頻區與View區大小同樣. 這樣在不一樣尺寸的手機上,視頻看起來不會變形,只是水平或豎直方向的兩端被裁剪了一些.
    private void transformVideo(int videoWidth, int videoHeight) {
        if (getHeight() == 0 || getWidth() == 0) {
            Log.d(TAG, "transformVideo, getHeight=" + getHeight() + "," + "getWidth=" + getWidth());
            return;
        }
        float sx = (float) getWidth() / (float) videoWidth;
        float sy = (float) getHeight() / (float) videoHeight;
        Log.d(TAG, "transformVideo, sx=" + sx);
        Log.d(TAG, "transformVideo, sy=" + sy);

        float maxScale = Math.max(sx, sy);
        if (this.matrix == null) {
            matrix = new Matrix();
        } else {
            matrix.reset();
        }

        //第2步:把視頻區移動到View區,使二者中心點重合.
        matrix.preTranslate((getWidth() - videoWidth) / 2, (getHeight() - videoHeight) / 2);

        //第1步:由於默認視頻是fitXY的形式顯示的,因此首先要縮放還原回來.
        matrix.preScale(videoWidth / (float) getWidth(), videoHeight / (float) getHeight());

        //第3步,等比例放大或縮小,直到視頻區的一邊超過View一邊, 另外一邊與View的另外一邊相等. 由於超過的部分超出了View的範圍,因此是不會顯示的,至關於裁剪了.
        matrix.postScale(maxScale, maxScale, getWidth() / 2, getResizedHeight() / 2);//後兩個參數座標是以整個View的座標系以參考的

        Log.d(TAG, "transformVideo, maxScale=" + maxScale);

        setTransform(matrix);
        postInvalidate();
        Log.d(TAG, "transformVideo, videoWidth=" + videoWidth + "," + "videoHeight=" + videoHeight);
    }

而後在OnVideoSizeChangedListener裏面監聽獲取到了視頻的實際尺寸後調用以上方法便可. spa

完整項目代碼: https://github.com/linsea/MatrixScale
code

相關文章
相關標籤/搜索