1227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/* 2227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Copyright (C) 2011 The Android Open Source Project 3227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 4227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Licensed under the Apache License, Version 2.0 (the "License"); 5227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * you may not use this file except in compliance with the License. 6227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * You may obtain a copy of the License at 7227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 8227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * http://www.apache.org/licenses/LICENSE-2.0 9227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 10227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Unless required by applicable law or agreed to in writing, software 11227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * distributed under the License is distributed on an "AS IS" BASIS, 12227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * See the License for the specific language governing permissions and 14227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * limitations under the License. 15227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 16227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 17227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspackage androidx.media.filterpacks.image; 18227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 19227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.Bitmap; 20227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.Canvas; 21227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.Color; 22227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.Paint; 23227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.Rect; 24227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.RectF; 25227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.view.Surface; 26227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.view.SurfaceHolder; 27227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.view.SurfaceView; 28227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.view.View; 29227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 30227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.FrameImage2D; 31227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.FrameType; 32227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.ImageShader; 33227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.InputPort; 34227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.MffContext; 35227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.RenderTarget; 36227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.Signature; 37227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.ViewFilter; 38227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 39227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspublic class SurfaceHolderTarget extends ViewFilter { 40227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 41227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private SurfaceHolder mSurfaceHolder = null; 42227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private RenderTarget mRenderTarget = null; 43227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private ImageShader mShader = null; 44227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private boolean mHasSurface = false; 45227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 46227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private SurfaceHolder.Callback mSurfaceHolderListener = new SurfaceHolder.Callback() { 47227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 48227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 49227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // This just makes sure the holder is still the one we expect. 50227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks onSurfaceCreated(holder); 51227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 52227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 53227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 54227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void surfaceCreated (SurfaceHolder holder) { 55227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks onSurfaceCreated(holder); 56227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 57227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 58227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 59227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void surfaceDestroyed (SurfaceHolder holder) { 60227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks onDestroySurface(); 61227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 62227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks }; 63227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 64227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public SurfaceHolderTarget(MffContext context, String name) { 65227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks super(context, name); 66227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 67227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 68227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 69227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void onBindToView(View view) { 70227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (view instanceof SurfaceView) { 71227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks SurfaceHolder holder = ((SurfaceView)view).getHolder(); 72227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (holder == null) { 73227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new RuntimeException("Could not get SurfaceHolder from SurfaceView " 74227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks + view + "!"); 75227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 76227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks setSurfaceHolder(holder); 77227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else { 78227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new IllegalArgumentException("View must be a SurfaceView!"); 79227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 80227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 81227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 82227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void setSurfaceHolder(SurfaceHolder holder) { 83227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (isRunning()) { 84227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new IllegalStateException("Cannot set SurfaceHolder while running!"); 85227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 86227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mSurfaceHolder = holder; 87227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 88227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 89227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized void onDestroySurface() { 90227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mRenderTarget != null) { 91227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRenderTarget.release(); 92227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRenderTarget = null; 93227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 94227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mHasSurface = false; 95227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 96227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 97227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 98227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public Signature getSignature() { 99227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks FrameType imageType = FrameType.image2D(FrameType.ELEMENT_RGBA8888, FrameType.READ_GPU); 100227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return super.getSignature() 101227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks .addInputPort("image", Signature.PORT_REQUIRED, imageType) 102227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks .disallowOtherPorts(); 103227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 104227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 105227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 106227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected void onInputPortOpen(InputPort port) { 107227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks super.connectViewInputs(port); 108227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 109227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 110227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 111227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected synchronized void onPrepare() { 112227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (isOpenGLSupported()) { 113227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mShader = ImageShader.createIdentity(); 114227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 115227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 116227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 117227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 118227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected synchronized void onOpen() { 119227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mSurfaceHolder.addCallback(mSurfaceHolderListener); 120227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Surface surface = mSurfaceHolder.getSurface(); 121227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mHasSurface = (surface != null) && surface.isValid(); 122227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 123227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 124227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 125227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected synchronized void onProcess() { 126227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks FrameImage2D image = getConnectedInputPort("image").pullFrame().asFrameImage2D(); 127227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mHasSurface) { 128227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Synchronize the surface holder in case another filter is accessing this surface. 129227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks synchronized (mSurfaceHolder) { 130227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (isOpenGLSupported()) { 131227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks renderGL(image); 132227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else { 133227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks renderCanvas(image); 134227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 135227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 136227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 137227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 138227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 139227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 140227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Renders the given frame to the screen using GLES2. 141227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @param image the image to render 142227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 143227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private void renderGL(FrameImage2D image) { 144227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mRenderTarget == null) { 145227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRenderTarget = RenderTarget.currentTarget().forSurfaceHolder(mSurfaceHolder); 146227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRenderTarget.registerAsDisplaySurface(); 147227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 148227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Rect frameRect = new Rect(0, 0, image.getWidth(), image.getHeight()); 149227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Rect surfRect = mSurfaceHolder.getSurfaceFrame(); 150227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks setupShader(mShader, frameRect, surfRect); 151227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mShader.process(image.lockTextureSource(), 152227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRenderTarget, 153227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks surfRect.width(), 154227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks surfRect.height()); 155227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks image.unlock(); 156227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRenderTarget.swapBuffers(); 157227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 158227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 159227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 160227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Renders the given frame to the screen using a Canvas. 161227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @param image the image to render 162227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 163227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private void renderCanvas(FrameImage2D image) { 164227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Canvas canvas = mSurfaceHolder.lockCanvas(); 165227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Bitmap bitmap = image.toBitmap(); 166227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Rect sourceRect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); 167227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Rect surfaceRect = mSurfaceHolder.getSurfaceFrame(); 168227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks RectF targetRect = getTargetRect(sourceRect, surfaceRect); 169227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks canvas.drawColor(Color.BLACK); 170227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (targetRect.width() > 0 && targetRect.height() > 0) { 171227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks canvas.scale(surfaceRect.width(), surfaceRect.height()); 172227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks canvas.drawBitmap(bitmap, sourceRect, targetRect, new Paint()); 173227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 174227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mSurfaceHolder.unlockCanvasAndPost(canvas); 175227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 176227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 177227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 178227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected synchronized void onClose() { 179227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mRenderTarget != null) { 180227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRenderTarget.unregisterAsDisplaySurface(); 181227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRenderTarget.release(); 182227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRenderTarget = null; 183227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 184227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mSurfaceHolder != null) { 185227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mSurfaceHolder.removeCallback(mSurfaceHolderListener); 186227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 187227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 188227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 189227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private synchronized void onSurfaceCreated(SurfaceHolder holder) { 190227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mSurfaceHolder != holder) { 191227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new RuntimeException("Unexpected Holder!"); 192227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 193227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mHasSurface = true; 194227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 195227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 196227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks} 197227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 198