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