diff --git a/encoder/src/main/java/com/pedro/encoder/input/gl/render/ScreenRender.java b/encoder/src/main/java/com/pedro/encoder/input/gl/render/ScreenRender.java index fae239e8e..e5818601a 100644 --- a/encoder/src/main/java/com/pedro/encoder/input/gl/render/ScreenRender.java +++ b/encoder/src/main/java/com/pedro/encoder/input/gl/render/ScreenRender.java @@ -24,6 +24,7 @@ import androidx.annotation.RequiresApi; import com.pedro.encoder.R; +import com.pedro.encoder.utils.ViewPort; import com.pedro.encoder.utils.gl.AspectRatioMode; import com.pedro.encoder.utils.gl.GlUtil; import com.pedro.encoder.utils.gl.SizeCalculator; @@ -32,6 +33,8 @@ import java.nio.ByteOrder; import java.nio.FloatBuffer; +import kotlin.Pair; + /** * Created by pedro on 29/01/18. */ @@ -92,8 +95,9 @@ public void draw(int width, int height, AspectRatioMode mode, int rotation, boolean flipStreamVertical, boolean flipStreamHorizontal) { GlUtil.checkGlError("drawScreen start"); - SizeCalculator.processMatrix(rotation, flipStreamHorizontal, flipStreamVertical, MVPMatrix); - SizeCalculator.calculateViewPort(mode, width, height, streamWidth, streamHeight); + updateMatrix(rotation, SizeCalculator.calculateFlip(flipStreamHorizontal, flipStreamVertical), MVPMatrix); + ViewPort viewport = SizeCalculator.calculateViewPort(mode, width, height, streamWidth, streamHeight); + GLES20.glViewport(viewport.getX(), viewport.getY(), viewport.getWidth(), viewport.getHeight()); draw(); } @@ -102,8 +106,9 @@ public void drawEncoder(int width, int height, boolean isPortrait, int rotation, boolean flipStreamVertical, boolean flipStreamHorizontal) { GlUtil.checkGlError("drawScreen start"); - SizeCalculator.processMatrix(rotation, flipStreamHorizontal, flipStreamVertical, MVPMatrix); - SizeCalculator.calculateViewPortEncoder(width, height, isPortrait); + updateMatrix(rotation, SizeCalculator.calculateFlip(flipStreamHorizontal, flipStreamVertical), MVPMatrix); + ViewPort viewport = SizeCalculator.calculateViewPortEncoder(width, height, isPortrait); + GLES20.glViewport(viewport.getX(), viewport.getY(), viewport.getWidth(), viewport.getHeight()); draw(); } @@ -112,7 +117,7 @@ public void drawPreview(int width, int height, boolean isPortrait, AspectRatioMode mode, int rotation, boolean flipStreamVertical, boolean flipStreamHorizontal) { GlUtil.checkGlError("drawScreen start"); - SizeCalculator.processMatrix(rotation, flipStreamHorizontal, flipStreamVertical, MVPMatrix); + updateMatrix(rotation, SizeCalculator.calculateFlip(flipStreamHorizontal, flipStreamVertical), MVPMatrix); float factor = (float) streamWidth / (float) streamHeight; int w; int h; @@ -123,7 +128,8 @@ public void drawPreview(int width, int height, boolean isPortrait, w = isPortrait ? streamWidth : streamHeight; h = isPortrait ? streamHeight : streamWidth; } - SizeCalculator.calculateViewPort(mode, width, height, w, h); + ViewPort viewport = SizeCalculator.calculateViewPort(mode, width, height, w, h); + GLES20.glViewport(viewport.getX(), viewport.getY(), viewport.getWidth(), viewport.getHeight()); draw(); } @@ -168,4 +174,10 @@ public void setStreamSize(int streamWidth, int streamHeight) { this.streamWidth = streamWidth; this.streamHeight = streamHeight; } + + private void updateMatrix(int rotation, Pair scale, float[] MVPMatrix) { + Matrix.setIdentityM(MVPMatrix, 0); + Matrix.scaleM(MVPMatrix, 0, scale.getFirst(), scale.getSecond(), 1f); + Matrix.rotateM(MVPMatrix, 0, rotation, 0f, 0f, -1f); + } } diff --git a/encoder/src/main/java/com/pedro/encoder/utils/ViewPort.kt b/encoder/src/main/java/com/pedro/encoder/utils/ViewPort.kt new file mode 100644 index 000000000..41f9be49a --- /dev/null +++ b/encoder/src/main/java/com/pedro/encoder/utils/ViewPort.kt @@ -0,0 +1,8 @@ +package com.pedro.encoder.utils + +data class ViewPort( + val x: Int, + val y: Int, + val width: Int, + val height: Int +) diff --git a/encoder/src/main/java/com/pedro/encoder/utils/gl/SizeCalculator.java b/encoder/src/main/java/com/pedro/encoder/utils/gl/SizeCalculator.java index 14e6d1e86..2a13bf218 100644 --- a/encoder/src/main/java/com/pedro/encoder/utils/gl/SizeCalculator.java +++ b/encoder/src/main/java/com/pedro/encoder/utils/gl/SizeCalculator.java @@ -16,11 +16,9 @@ package com.pedro.encoder.utils.gl; -import android.graphics.Point; -import android.graphics.PointF; -import android.opengl.GLES20; -import android.opengl.Matrix; -import android.util.Pair; +import com.pedro.encoder.utils.ViewPort; + +import kotlin.Pair; /** * Created by pedro on 22/03/19. @@ -28,102 +26,59 @@ public class SizeCalculator { - public static void calculateViewPort(AspectRatioMode mode, int previewWidth, + public static ViewPort calculateViewPort(AspectRatioMode mode, int previewWidth, int previewHeight, int streamWidth, int streamHeight) { - Pair pair = - getViewport(mode, previewWidth, previewHeight, streamWidth, streamHeight); - GLES20.glViewport(pair.first.x, pair.first.y, pair.second.x, pair.second.y); + if (mode == AspectRatioMode.NONE) { + return new ViewPort(0, 0, previewWidth, previewHeight); + } + float streamAspectRatio = (float) streamWidth / (float) streamHeight; + float previewAspectRatio = (float) previewWidth / (float) previewHeight; + int xo = 0; + int yo = 0; + int xf = previewWidth; + int yf = previewHeight; + if (mode == AspectRatioMode.Adjust) { + if (streamAspectRatio > previewAspectRatio) { + yf = streamHeight * previewWidth / streamWidth; + yo = (yf - previewHeight) / -2; + } else { + xf = streamWidth * previewHeight / streamHeight; + xo = (xf - previewWidth) / -2; + } + } else { //AspectRatioMode.Fill + if (streamAspectRatio > previewAspectRatio) { + xf = streamWidth * previewHeight / streamHeight; + xo = (xf - previewWidth) / -2; + } else { + yf = streamHeight * previewWidth / streamWidth; + yo = (yf - previewHeight) / -2; + } + } + return new ViewPort(xo, yo, xf, yf); } - public static void calculateViewPortEncoder(int streamWidth, int streamHeight, boolean isPortrait) { - Pair pair; + public static ViewPort calculateViewPortEncoder(int streamWidth, int streamHeight, boolean isPortrait) { float factor = (float) streamWidth / (float) streamHeight; if (factor >= 1f) { if (isPortrait) { int width = (int) (streamHeight / factor); int oX = (streamWidth - width) / 2; - pair = new Pair<>(new Point(oX, 0), new Point(width, streamHeight)); + return new ViewPort(oX, 0, width, streamHeight); } else { - pair = new Pair<>(new Point(0, 0), new Point(streamWidth, streamHeight)); + return new ViewPort(0, 0, streamWidth, streamHeight); } } else { if (isPortrait) { - pair = new Pair<>(new Point(0, 0), new Point(streamWidth, streamHeight)); + return new ViewPort(0, 0, streamWidth, streamHeight); } else { int height = (int) (streamWidth * factor); int oY = (streamHeight - height) / 2; - pair = new Pair<>(new Point(0, oY), new Point(streamWidth, height)); + return new ViewPort(0, oY, streamWidth, height); } } - GLES20.glViewport(pair.first.x, pair.first.y, pair.second.x, pair.second.y); } - public static Pair getViewport(AspectRatioMode mode, int previewWidth, - int previewHeight, int streamWidth, int streamHeight) { - if (mode != AspectRatioMode.NONE) { - float streamAspectRatio = (float) streamWidth / (float) streamHeight; - float previewAspectRatio = (float) previewWidth / (float) previewHeight; - int xo = 0; - int yo = 0; - int xf = previewWidth; - int yf = previewHeight; - if ((previewAspectRatio > 1f && streamAspectRatio > previewAspectRatio) || - (streamAspectRatio <= 1f && previewAspectRatio <= 1 && streamAspectRatio > previewAspectRatio) || - (streamAspectRatio > 1f && previewAspectRatio < 1f)) { - if (mode == AspectRatioMode.Adjust) { - yf = streamHeight * previewWidth / streamWidth; - yo = (yf - previewHeight) / -2; - } else { //fill - xf = streamWidth * previewHeight / streamHeight; - xo = (xf - previewWidth) / -2; - } - } else if ((streamAspectRatio >= 1f && previewAspectRatio >= 1f && streamAspectRatio < previewAspectRatio) || - (previewAspectRatio < 1f && streamAspectRatio < previewAspectRatio) || - (streamAspectRatio < 1f && previewAspectRatio > 1f)) { - if (mode == AspectRatioMode.Adjust) { - xf = streamWidth * previewHeight / streamHeight; - xo = (xf - previewWidth) / -2; - } else { - yf = streamHeight * previewWidth / streamWidth; - yo = (yf - previewHeight) / -2; - } - } - return new Pair<>(new Point(xo, yo), new Point(xf, yf)); - } else { - return new Pair<>(new Point(0, 0), new Point(previewWidth, previewHeight)); - } - } - - public static void processMatrix(int rotation, boolean flipStreamHorizontal, - boolean flipStreamVertical, float[] MVPMatrix) { - PointF scale = new PointF(1f, 1f); - - float xFlip = flipStreamHorizontal ? -1f : 1f; - float yFlip = flipStreamVertical ? -1f : 1f; - scale = new PointF(scale.x * xFlip, scale.y * yFlip); - - updateMatrix(rotation, scale, MVPMatrix); - } - - private static void updateMatrix(int rotation, PointF scale, float[] MVPMatrix) { - Matrix.setIdentityM(MVPMatrix, 0); - Matrix.scaleM(MVPMatrix, 0, scale.x, scale.y, 1f); - Matrix.rotateM(MVPMatrix, 0, rotation, 0f, 0f, -1f); - } - - private static PointF getScale(int rotation, int width, int height, boolean isPortrait, - boolean isPreview) { - float scaleX = 1f; - float scaleY = 1f; - if (!isPreview) { - if (isPortrait && rotation != 0 && rotation != 180) { //portrait - final float adjustedWidth = width * (width / (float) height); - scaleY = adjustedWidth / height; - } else if (!isPortrait && rotation != 90 && rotation != 270) { //landscape - final float adjustedWidth = height * (height / (float) width); - scaleX = adjustedWidth / width; - } - } - return new PointF(scaleX, scaleY); + public static Pair calculateFlip(boolean flipStreamHorizontal, boolean flipStreamVertical) { + return new Pair<>(flipStreamHorizontal ? -1f : 1f, flipStreamVertical ? -1f : 1f); } } \ No newline at end of file diff --git a/encoder/src/test/java/com/pedro/encoder/SizeCalculatorTest.kt b/encoder/src/test/java/com/pedro/encoder/SizeCalculatorTest.kt new file mode 100644 index 000000000..972209280 --- /dev/null +++ b/encoder/src/test/java/com/pedro/encoder/SizeCalculatorTest.kt @@ -0,0 +1,78 @@ +package com.pedro.encoder + +import com.pedro.encoder.utils.ViewPort +import com.pedro.encoder.utils.gl.AspectRatioMode +import com.pedro.encoder.utils.gl.SizeCalculator +import junit.framework.TestCase.assertEquals +import org.junit.Test + + +class SizeCalculatorTest { + + @Test + fun `calculate viewport preview cases with adjust mode`() { + //higher aspect ratio than preview + val result = SizeCalculator.calculateViewPort(AspectRatioMode.Adjust, 100, 100, 160, 90) + assertEquals(ViewPort(0, 22, 100, 56), result) + //lower aspect ratio than preview + val result2 = SizeCalculator.calculateViewPort(AspectRatioMode.Adjust, 100, 100, 90, 160) + assertEquals(ViewPort(22, 0, 56, 100), result2) + //equal + val result3 = SizeCalculator.calculateViewPort(AspectRatioMode.Adjust, 100, 100, 100, 100) + assertEquals(ViewPort(0, 0, 100, 100), result3) + } + + @Test + fun `calculate viewport preview cases with fill mode`() { + //higher aspect ratio than preview + val result = SizeCalculator.calculateViewPort(AspectRatioMode.Fill, 100, 100, 160, 90) + assertEquals(ViewPort(-38, 0, 177, 100), result) + //lower aspect ratio than preview + val result2 = SizeCalculator.calculateViewPort(AspectRatioMode.Fill, 100, 100, 90, 160) + assertEquals(ViewPort(0, -38, 100, 177), result2) + //equal + val result3 = SizeCalculator.calculateViewPort(AspectRatioMode.Fill, 100, 100, 160, 90) + assertEquals(ViewPort(-38, 0, 177, 100), result3) + } + + @Test + fun `calculate viewport preview cases with none mode`() { + val result = SizeCalculator.calculateViewPort(AspectRatioMode.NONE, 100, 100, 160, 90) + assertEquals(ViewPort(0, 0, 100, 100), result) + val result2 = SizeCalculator.calculateViewPort(AspectRatioMode.NONE, 100, 100, 90, 160) + assertEquals(ViewPort(0, 0, 100, 100), result2) + val result3 = SizeCalculator.calculateViewPort(AspectRatioMode.NONE, 100, 100, 100, 100) + assertEquals(ViewPort(0, 0, 100, 100), result3) + } + + @Test + fun `calculate flipH and flipV cases`() { + val result = SizeCalculator.calculateFlip(true, true) + assertEquals(Pair(-1f, -1f), result) + val result2 = SizeCalculator.calculateFlip(false, false) + assertEquals(Pair(1f, 1f), result2) + val result3 = SizeCalculator.calculateFlip(true, false) + assertEquals(Pair(-1f, 1f), result3) + val result4 = SizeCalculator.calculateFlip(false, true) + assertEquals(Pair(1f, -1f), result4) + } + + @Test + fun `calculate viewport encoder cases`() { + //aspect ratio factor > 1f + val result = SizeCalculator.calculateViewPortEncoder(160, 90, true) + assertEquals(ViewPort(55, 0, 50, 90), result) + val result2 = SizeCalculator.calculateViewPortEncoder(160, 90, false) + assertEquals(ViewPort(0, 0, 160, 90), result2) + //aspect ratio factor < 1f + val result3 = SizeCalculator.calculateViewPortEncoder(90, 160, true) + assertEquals(ViewPort(0, 0, 90, 160), result3) + val result4 = SizeCalculator.calculateViewPortEncoder(90, 160, false) + assertEquals(ViewPort(0, 55, 90, 50), result4) + //aspect ratio factor = 1f + val result5 = SizeCalculator.calculateViewPortEncoder(100, 100, true) + assertEquals(ViewPort(0, 0, 100, 100), result5) + val result6 = SizeCalculator.calculateViewPortEncoder(100, 100, false) + assertEquals(ViewPort(0, 0, 100, 100), result6) + } +} \ No newline at end of file