diff --git a/epf/src/main/java/com/daasuu/epf/EPlayerRenderer.java b/epf/src/main/java/com/daasuu/epf/EPlayerRenderer.java index 74b37e7..0c03035 100644 --- a/epf/src/main/java/com/daasuu/epf/EPlayerRenderer.java +++ b/epf/src/main/java/com/daasuu/epf/EPlayerRenderer.java @@ -77,7 +77,7 @@ public void run() { @Override public void onSurfaceCreated(final EGLConfig config) { - GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); final int[] args = new int[1]; @@ -136,6 +136,8 @@ public void onSurfaceChanged(final int width, final int height) { @Override public void onDrawFrame(final EFramebufferObject fbo) { + GLES20.glEnable(GLES20.GL_BLEND); + GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); synchronized (this) { if (updateSurface) { diff --git a/epf/src/main/java/com/daasuu/epf/EPlayerTranslucentView.java b/epf/src/main/java/com/daasuu/epf/EPlayerTranslucentView.java new file mode 100644 index 0000000..69ce8c2 --- /dev/null +++ b/epf/src/main/java/com/daasuu/epf/EPlayerTranslucentView.java @@ -0,0 +1,19 @@ +package com.daasuu.epf; + +import android.content.Context; +import android.util.AttributeSet; + +/** + * Created by LukeNeedham on 2020/01/14. + */ +public class EPlayerTranslucentView extends EPlayerView { + + public EPlayerTranslucentView(Context context) { + this(context, null); + } + + public EPlayerTranslucentView(Context context, AttributeSet attrs) { + super(context, attrs); + setZOrderOnTop(true); + } +} diff --git a/epf/src/main/java/com/daasuu/epf/EPlayerView.java b/epf/src/main/java/com/daasuu/epf/EPlayerView.java index ef88354..aa60c5e 100644 --- a/epf/src/main/java/com/daasuu/epf/EPlayerView.java +++ b/epf/src/main/java/com/daasuu/epf/EPlayerView.java @@ -1,6 +1,7 @@ package com.daasuu.epf; import android.content.Context; +import android.graphics.PixelFormat; import android.opengl.GLSurfaceView; import android.util.AttributeSet; @@ -10,6 +11,8 @@ import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.video.VideoListener; +import static com.daasuu.epf.chooser.EConfigChooser.EGL_CONTEXT_CLIENT_VERSION; + /** * Created by sudamasayuki on 2017/05/16. */ @@ -20,7 +23,14 @@ public class EPlayerView extends GLSurfaceView implements VideoListener { private final EPlayerRenderer renderer; private SimpleExoPlayer player; - private float videoAspect = 1f; + /* Video Aspect according to the video */ + private float measuredVideoAspect = 1f; + + /* Video Aspect according to the video, adjusted to the needs of the filter */ + private float adjustedVideoAspect = measuredVideoAspect; + + private GlFilter glFilter = null; + private PlayerScaleType playerScaleType = PlayerScaleType.RESIZE_FIT_WIDTH; public EPlayerView(Context context) { @@ -31,11 +41,13 @@ public EPlayerView(Context context, AttributeSet attrs) { super(context, attrs); setEGLContextFactory(new EContextFactory()); - setEGLConfigChooser(new EConfigChooser()); + + setEGLConfigChooser(new EConfigChooser(8, 8, 8, 8, 16, 0, EGL_CONTEXT_CLIENT_VERSION)); + + getHolder().setFormat(PixelFormat.RGBA_8888); renderer = new EPlayerRenderer(this); setRenderer(renderer); - } public EPlayerView setSimpleExoPlayer(SimpleExoPlayer player) { @@ -50,7 +62,12 @@ public EPlayerView setSimpleExoPlayer(SimpleExoPlayer player) { } public void setGlFilter(GlFilter glFilter) { + this.glFilter = glFilter; renderer.setGlFilter(glFilter); + + adjustedVideoAspect = calculateAdjustedVideoAspect(); + + requestLayout(); } public void setPlayerScaleType(PlayerScaleType playerScaleType) { @@ -70,10 +87,10 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { switch (playerScaleType) { case RESIZE_FIT_WIDTH: - viewHeight = (int) (measuredWidth / videoAspect); + viewHeight = (int) (measuredWidth / adjustedVideoAspect); break; case RESIZE_FIT_HEIGHT: - viewWidth = (int) (measuredHeight * videoAspect); + viewWidth = (int) (measuredHeight * adjustedVideoAspect); break; } @@ -95,8 +112,10 @@ public void onPause() { @Override public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { // Log.d(TAG, "width = " + width + " height = " + height + " unappliedRotationDegrees = " + unappliedRotationDegrees + " pixelWidthHeightRatio = " + pixelWidthHeightRatio); - videoAspect = ((float) width / height) * pixelWidthHeightRatio; - // Log.d(TAG, "videoAspect = " + videoAspect); + measuredVideoAspect = ((float) width / height) * pixelWidthHeightRatio; + adjustedVideoAspect = calculateAdjustedVideoAspect(); + // Log.d(TAG, "measuredVideoAspect = " + measuredVideoAspect); + requestLayout(); } @@ -104,4 +123,12 @@ public void onVideoSizeChanged(int width, int height, int unappliedRotationDegre public void onRenderedFirstFrame() { // do nothing } + + private float calculateAdjustedVideoAspect() { + if (glFilter == null) { + return measuredVideoAspect; + } else { + return glFilter.getVideoAspect(measuredVideoAspect); + } + } } diff --git a/epf/src/main/java/com/daasuu/epf/chooser/EConfigChooser.java b/epf/src/main/java/com/daasuu/epf/chooser/EConfigChooser.java index 4f77625..550e15c 100644 --- a/epf/src/main/java/com/daasuu/epf/chooser/EConfigChooser.java +++ b/epf/src/main/java/com/daasuu/epf/chooser/EConfigChooser.java @@ -30,10 +30,10 @@ public class EConfigChooser implements GLSurfaceView.EGLConfigChooser { private final int depthSize; private final int stencilSize; - private static final int EGL_CONTEXT_CLIENT_VERSION = 2; - private static final boolean USE_RGB_888 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1; + public static final int EGL_CONTEXT_CLIENT_VERSION = 2; + public EConfigChooser() { this( USE_RGB_888 ? 8 : 5, diff --git a/epf/src/main/java/com/daasuu/epf/filter/AlphaFrameFilter.java b/epf/src/main/java/com/daasuu/epf/filter/AlphaFrameFilter.java new file mode 100644 index 0000000..8431845 --- /dev/null +++ b/epf/src/main/java/com/daasuu/epf/filter/AlphaFrameFilter.java @@ -0,0 +1,85 @@ +package com.daasuu.epf.filter; + +/** + * Also known as Luma Matte. + * Used for videos which comprise half of content, and half of alpha-mask / luma-matte. + * The result is a video containing only content, masked by the alpha-mask to add transparency. + *

+ * To use this filter, you need to use a EPlayerTranslucentView rather than an ordinary EPlayerView. + *

+ * Or, use an EPlayerView and ensure you call `EPlayerView.setZOrderOnTop(true)` + * before the surface view's containing window is attached to the window manager + */ +public class AlphaFrameFilter extends GlFilter { + + private static final String VERTEX_SHADER = + "attribute vec4 aPosition;\n" + + "attribute vec4 aTextureCoord;\n" + + "varying highp vec2 vTextureCoordContent;\n" + + "varying highp vec2 vTextureCoordMask;\n" + + "void main() {\n" + + "gl_Position = aPosition;\n" + + "vTextureCoordContent = %s;\n" + + "vTextureCoordMask = %s;\n" + + "}\n"; + + private static final String FRAGMENT_SHADER = + "precision mediump float;\n" + + "varying highp vec2 vTextureCoordContent;\n" + + "varying highp vec2 vTextureCoordMask;\n" + + "uniform lowp sampler2D sTexture;\n" + + "void main() {\n" + + "vec4 colorContent = texture2D(sTexture, vTextureCoordContent);\n" + + "vec4 colorMask = texture2D(sTexture, vTextureCoordMask);\n" + + "gl_FragColor = vec4(colorContent.rgb, colorMask.r);\n" + + "}\n"; + + private AlphaMaskPosition alphaMaskPosition; + + /** + * @param alphaMaskPosition the position of the alpha-mask in the video. + */ + public AlphaFrameFilter(AlphaMaskPosition alphaMaskPosition) { + super(getVertexShader(alphaMaskPosition), FRAGMENT_SHADER); + this.alphaMaskPosition = alphaMaskPosition; + } + + @Override + public float getVideoAspect(float originalVideoAspect) { + float factor; + if (alphaMaskPosition == AlphaMaskPosition.TOP || alphaMaskPosition == AlphaMaskPosition.BOTTOM) { + factor = 2f; + } else { + factor = 1f / 2f; + } + return originalVideoAspect * factor; + } + + private static String getVertexShader(AlphaMaskPosition alphaMaskPosition) { + String vTextureCoordContent; + String vTextureCoordMask; + + // Note: LEFT and TOP are untested! If funky stuff is occurring, check here + if (alphaMaskPosition == AlphaMaskPosition.LEFT) { + vTextureCoordContent = "vec2(aTextureCoord.x*0.5+0.5, aTextureCoord.y)"; + vTextureCoordMask = "vec2(aTextureCoord.x*0.5, aTextureCoord.y)"; + } else if (alphaMaskPosition == AlphaMaskPosition.TOP) { + vTextureCoordContent = "vec2(aTextureCoord.x, aTextureCoord.y*0.5)"; + vTextureCoordMask = "vec2(aTextureCoord.x, aTextureCoord.y*0.5+0.5)"; + } else if (alphaMaskPosition == AlphaMaskPosition.RIGHT) { + vTextureCoordContent = "vec2(aTextureCoord.x*0.5, aTextureCoord.y)"; + vTextureCoordMask = "vec2(aTextureCoord.x*0.5+0.5, aTextureCoord.y)"; + } else if (alphaMaskPosition == AlphaMaskPosition.BOTTOM) { + vTextureCoordContent = "vec2(aTextureCoord.x, aTextureCoord.y*0.5+0.5)"; + vTextureCoordMask = "vec2(aTextureCoord.x, aTextureCoord.y*0.5)"; + } else { + throw new RuntimeException("No vertex shader found for alphaMaskPosition" + alphaMaskPosition); + } + + return String.format(VERTEX_SHADER, vTextureCoordContent, vTextureCoordMask); + } + + public enum AlphaMaskPosition { + LEFT, TOP, RIGHT, BOTTOM + } +} \ No newline at end of file diff --git a/epf/src/main/java/com/daasuu/epf/filter/GlFilter.java b/epf/src/main/java/com/daasuu/epf/filter/GlFilter.java index 1a399aa..9e692ae 100644 --- a/epf/src/main/java/com/daasuu/epf/filter/GlFilter.java +++ b/epf/src/main/java/com/daasuu/epf/filter/GlFilter.java @@ -130,6 +130,10 @@ public void draw(final int texName, final EFramebufferObject fbo) { GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); } + public float getVideoAspect(float originalVideoAspect) { + return originalVideoAspect; + } + protected void onDraw() { }