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