Home | History | Annotate | Download | only in filterfw
      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