1. 程式人生 > >android視訊適配與裁剪

android視訊適配與裁剪

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

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

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

最近開發有如下需求:

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

以上需求用系統的VideoView是無法達到的,所以要自定義VideoView.

最終我們擴充套件TextureView來自定義一個TextureVideoView, 並應用Matrix進行縮放, 也即是要求出變換的Matrix, 主要按以下步驟來即可求出變換矩陣, 這裡直接貼出程式碼:

//需求:視訊等比例放大,直至一邊鋪滿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裡面監聽獲取到了視訊的實際尺寸後呼叫以上方法即可.