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.filterfw;
18227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
19227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.Bitmap;
20227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.Canvas;
21227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.Paint;
22227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.Rect;
23227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.RectF;
24227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport androidx.media.filterfw.BackingStore.Backing;
25227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
26227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspublic class FrameImage2D extends FrameBuffer2D {
27227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
28227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
29227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Access frame's data using a TextureSource.
30227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * This is a convenience method and is equivalent to calling {@code lockData} with an
31227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * {@code accessFormat} of {@code ACCESS_TEXTURE}.
32227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
33227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return The TextureSource instance holding the Frame's data.
34227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
35227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public TextureSource lockTextureSource() {
36227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return (TextureSource)mBackingStore.lockData(MODE_READ, BackingStore.ACCESS_TEXTURE);
37227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
38227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
39227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
40227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Access frame's data using a RenderTarget.
41227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * This is a convenience method and is equivalent to calling {@code lockData} with an
42227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * {@code accessFormat} of {@code ACCESS_RENDERTARGET}.
43227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
44227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return The RenderTarget instance holding the Frame's data.
45227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
46227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public RenderTarget lockRenderTarget() {
47227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return (RenderTarget)mBackingStore.lockData(MODE_WRITE, BackingStore.ACCESS_RENDERTARGET);
48227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
49227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
50227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
51227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Assigns the pixel data of the specified bitmap.
52227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
53227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * The RGBA pixel data will be extracted from the bitmap and assigned to the frame data. Note,
54227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * that the colors are premultiplied with the alpha channel. If you wish to have
55227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * non-premultiplied colors, you must pass the Frame through an
56227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * {@code UnpremultiplyAlphaFilter}.
57227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
58227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param bitmap The bitmap pixels to assign.
59227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
60227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void setBitmap(Bitmap bitmap) {
61227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        bitmap = convertToFrameType(bitmap, mBackingStore.getFrameType());
62227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        validateBitmapSize(bitmap, mBackingStore.getDimensions());
63227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        Backing backing = mBackingStore.lockBacking(MODE_WRITE, BackingStore.ACCESS_BITMAP);
64227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        backing.setData(bitmap);
65227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mBackingStore.unlock();
66227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
67227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
68227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
69227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the RGBA image contents as a Bitmap instance.
70227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
71227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return a Bitmap instance holding the RGBA Frame image content.
72227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
73227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public Bitmap toBitmap() {
74227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        Bitmap result = (Bitmap)mBackingStore.lockData(MODE_READ, BackingStore.ACCESS_BITMAP);
75227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mBackingStore.unlock();
76227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return result;
77227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
78227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
79227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
80227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Copies the image data from one frame to another.
81227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
82227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * The source and target rectangles must be given in normalized coordinates, where 0,0 is the
83227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * top-left of the image and 1,1 is the bottom-right.
84227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
85227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * If the target rectangle is smaller than the target frame, the pixel values outside of the
86227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * target rectangle are undefined.
87227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
88227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * This method must be called within a Filter during execution. It supports both GL-enabled
89227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * and GL-disabled run contexts.
90227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
91227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param target The target frame to copy to.
92227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param sourceRect The source rectangle in normalized coordinates.
93227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param targetRect The target rectangle in normalized coordinates.
94227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
95227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public void copyToFrame(FrameImage2D target, RectF sourceRect, RectF targetRect) {
96227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (GraphRunner.current().isOpenGLSupported()) {
97227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            gpuImageCopy(this, target, sourceRect, targetRect);
98227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        } else {
99227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            cpuImageCopy(this, target, sourceRect, targetRect);
100227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
101227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
102227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
103227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    static FrameImage2D create(BackingStore backingStore) {
104227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        assertCanCreate(backingStore);
105227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return new FrameImage2D(backingStore);
106227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
107227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
108227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    FrameImage2D(BackingStore backingStore) {
109227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        super(backingStore);
110227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
111227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
112227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    static void assertCanCreate(BackingStore backingStore) {
113227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        FrameBuffer2D.assertCanCreate(backingStore);
114227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
115227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
116227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static Bitmap convertToFrameType(Bitmap bitmap, FrameType type) {
117227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        Bitmap.Config config = bitmap.getConfig();
118227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        Bitmap result = bitmap;
119227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        switch(type.getElementId()) {
120227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            case FrameType.ELEMENT_RGBA8888:
121227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                if (config != Bitmap.Config.ARGB_8888) {
122227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    result = bitmap.copy(Bitmap.Config.ARGB_8888, false);
123227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    if (result == null) {
124227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        throw new RuntimeException("Could not convert bitmap to frame-type " +
125227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                                "RGBA8888!");
126227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    }
127227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                }
128227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                break;
129227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            default:
130227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                throw new IllegalArgumentException("Unsupported frame type '" + type + "' for " +
131227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        "bitmap assignment!");
132227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
133227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return result;
134227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
135227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
136227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private void validateBitmapSize(Bitmap bitmap, int[] dimensions) {
137227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        if (bitmap.getWidth() != dimensions[0] || bitmap.getHeight() != dimensions[1]) {
138227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            throw new IllegalArgumentException("Cannot assign bitmap of size " + bitmap.getWidth()
139227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    + "x" + bitmap.getHeight() + " to frame of size " + dimensions[0] + "x"
140227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                    + dimensions[1] + "!");
141227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        }
142227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
143227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
144227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static void gpuImageCopy(
145227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            FrameImage2D srcImage, FrameImage2D dstImage, RectF srcRect, RectF dstRect) {
146227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        ImageShader idShader = RenderTarget.currentTarget().getIdentityShader();
147227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // We briefly modify the shader
148227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // TODO: Implement a safer way to save and restore a shared shader.
149227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        idShader.setSourceRect(srcRect);
150227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        idShader.setTargetRect(dstRect);
151227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        idShader.process(srcImage, dstImage);
152227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // And reset it as others may use it as well
153227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        idShader.setSourceRect(0f, 0f, 1f, 1f);
154227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        idShader.setTargetRect(0f, 0f, 1f, 1f);
155227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
156227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
157227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static void cpuImageCopy(
158227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            FrameImage2D srcImage, FrameImage2D dstImage, RectF srcRect, RectF dstRect) {
159227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // Convert rectangles to integer rectangles in image dimensions
160227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        Rect srcIRect = new Rect((int) srcRect.left * srcImage.getWidth(),
161227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                (int) srcRect.top * srcImage.getHeight(),
162227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                (int) srcRect.right * srcImage.getWidth(),
163227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                (int) srcRect.bottom * srcImage.getHeight());
164227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        Rect dstIRect = new Rect((int) dstRect.left * srcImage.getWidth(),
165227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                (int) dstRect.top * srcImage.getHeight(),
166227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                (int) dstRect.right * srcImage.getWidth(),
167227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                (int) dstRect.bottom * srcImage.getHeight());
168227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
169227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // Create target canvas
170227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        Bitmap.Config config = Bitmap.Config.ARGB_8888;
171227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        Bitmap dstBitmap = Bitmap.createBitmap(dstImage.getWidth(), dstImage.getHeight(), config);
172227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        Canvas canvas = new Canvas(dstBitmap);
173227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
174227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // Draw source bitmap into target canvas
175227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        Paint paint = new Paint();
176227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        paint.setFilterBitmap(true);
177227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        Bitmap srcBitmap = srcImage.toBitmap();
178227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        canvas.drawBitmap(srcBitmap, srcIRect, dstIRect, paint);
179227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
180227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // Assign bitmap to output frame
181227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        dstImage.setBitmap(dstBitmap);
182227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
183227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks}
184227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
185