1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.media.filterpacks.image; 18 19 import android.graphics.Bitmap; 20 import android.graphics.Canvas; 21 import android.graphics.Color; 22 import android.graphics.Paint; 23 import android.graphics.Rect; 24 import android.graphics.RectF; 25 import android.view.Surface; 26 import android.view.SurfaceHolder; 27 import android.view.SurfaceView; 28 import android.view.View; 29 30 import androidx.media.filterfw.FrameImage2D; 31 import androidx.media.filterfw.FrameType; 32 import androidx.media.filterfw.ImageShader; 33 import androidx.media.filterfw.InputPort; 34 import androidx.media.filterfw.MffContext; 35 import androidx.media.filterfw.RenderTarget; 36 import androidx.media.filterfw.Signature; 37 import androidx.media.filterfw.ViewFilter; 38 39 public class SurfaceHolderTarget extends ViewFilter { 40 41 private SurfaceHolder mSurfaceHolder = null; 42 private RenderTarget mRenderTarget = null; 43 private ImageShader mShader = null; 44 private boolean mHasSurface = false; 45 46 private SurfaceHolder.Callback mSurfaceHolderListener = new SurfaceHolder.Callback() { 47 @Override 48 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 49 // This just makes sure the holder is still the one we expect. 50 onSurfaceCreated(holder); 51 } 52 53 @Override 54 public void surfaceCreated (SurfaceHolder holder) { 55 onSurfaceCreated(holder); 56 } 57 58 @Override 59 public void surfaceDestroyed (SurfaceHolder holder) { 60 onDestroySurface(); 61 } 62 }; 63 64 public SurfaceHolderTarget(MffContext context, String name) { 65 super(context, name); 66 } 67 68 @Override 69 public void onBindToView(View view) { 70 if (view instanceof SurfaceView) { 71 SurfaceHolder holder = ((SurfaceView)view).getHolder(); 72 if (holder == null) { 73 throw new RuntimeException("Could not get SurfaceHolder from SurfaceView " 74 + view + "!"); 75 } 76 setSurfaceHolder(holder); 77 } else { 78 throw new IllegalArgumentException("View must be a SurfaceView!"); 79 } 80 } 81 82 public void setSurfaceHolder(SurfaceHolder holder) { 83 if (isRunning()) { 84 throw new IllegalStateException("Cannot set SurfaceHolder while running!"); 85 } 86 mSurfaceHolder = holder; 87 } 88 89 public synchronized void onDestroySurface() { 90 if (mRenderTarget != null) { 91 mRenderTarget.release(); 92 mRenderTarget = null; 93 } 94 mHasSurface = false; 95 } 96 97 @Override 98 public Signature getSignature() { 99 FrameType imageType = FrameType.image2D(FrameType.ELEMENT_RGBA8888, FrameType.READ_GPU); 100 return super.getSignature() 101 .addInputPort("image", Signature.PORT_REQUIRED, imageType) 102 .disallowOtherPorts(); 103 } 104 105 @Override 106 protected void onInputPortOpen(InputPort port) { 107 super.connectViewInputs(port); 108 } 109 110 @Override 111 protected synchronized void onPrepare() { 112 if (isOpenGLSupported()) { 113 mShader = ImageShader.createIdentity(); 114 } 115 } 116 117 @Override 118 protected synchronized void onOpen() { 119 mSurfaceHolder.addCallback(mSurfaceHolderListener); 120 Surface surface = mSurfaceHolder.getSurface(); 121 mHasSurface = (surface != null) && surface.isValid(); 122 } 123 124 @Override 125 protected synchronized void onProcess() { 126 FrameImage2D image = getConnectedInputPort("image").pullFrame().asFrameImage2D(); 127 if (mHasSurface) { 128 // Synchronize the surface holder in case another filter is accessing this surface. 129 synchronized (mSurfaceHolder) { 130 if (isOpenGLSupported()) { 131 renderGL(image); 132 } else { 133 renderCanvas(image); 134 } 135 } 136 } 137 } 138 139 /** 140 * Renders the given frame to the screen using GLES2. 141 * @param image the image to render 142 */ 143 private void renderGL(FrameImage2D image) { 144 if (mRenderTarget == null) { 145 mRenderTarget = RenderTarget.currentTarget().forSurfaceHolder(mSurfaceHolder); 146 mRenderTarget.registerAsDisplaySurface(); 147 } 148 Rect frameRect = new Rect(0, 0, image.getWidth(), image.getHeight()); 149 Rect surfRect = mSurfaceHolder.getSurfaceFrame(); 150 setupShader(mShader, frameRect, surfRect); 151 mShader.process(image.lockTextureSource(), 152 mRenderTarget, 153 surfRect.width(), 154 surfRect.height()); 155 image.unlock(); 156 mRenderTarget.swapBuffers(); 157 } 158 159 /** 160 * Renders the given frame to the screen using a Canvas. 161 * @param image the image to render 162 */ 163 private void renderCanvas(FrameImage2D image) { 164 Canvas canvas = mSurfaceHolder.lockCanvas(); 165 Bitmap bitmap = image.toBitmap(); 166 Rect sourceRect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); 167 Rect surfaceRect = mSurfaceHolder.getSurfaceFrame(); 168 RectF targetRect = getTargetRect(sourceRect, surfaceRect); 169 canvas.drawColor(Color.BLACK); 170 if (targetRect.width() > 0 && targetRect.height() > 0) { 171 canvas.scale(surfaceRect.width(), surfaceRect.height()); 172 canvas.drawBitmap(bitmap, sourceRect, targetRect, new Paint()); 173 } 174 mSurfaceHolder.unlockCanvasAndPost(canvas); 175 } 176 177 @Override 178 protected synchronized void onClose() { 179 if (mRenderTarget != null) { 180 mRenderTarget.unregisterAsDisplaySurface(); 181 mRenderTarget.release(); 182 mRenderTarget = null; 183 } 184 if (mSurfaceHolder != null) { 185 mSurfaceHolder.removeCallback(mSurfaceHolderListener); 186 } 187 } 188 189 private synchronized void onSurfaceCreated(SurfaceHolder holder) { 190 if (mSurfaceHolder != holder) { 191 throw new RuntimeException("Unexpected Holder!"); 192 } 193 mHasSurface = true; 194 } 195 196 } 197 198