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.filterfw; 18 19 import android.graphics.Bitmap; 20 import android.graphics.Canvas; 21 import android.graphics.Paint; 22 import android.graphics.Rect; 23 import android.graphics.RectF; 24 import androidx.media.filterfw.BackingStore.Backing; 25 26 public class FrameImage2D extends FrameBuffer2D { 27 28 /** 29 * Access frame's data using a TextureSource. 30 * This is a convenience method and is equivalent to calling {@code lockData} with an 31 * {@code accessFormat} of {@code ACCESS_TEXTURE}. 32 * 33 * @return The TextureSource instance holding the Frame's data. 34 */ 35 public TextureSource lockTextureSource() { 36 return (TextureSource)mBackingStore.lockData(MODE_READ, BackingStore.ACCESS_TEXTURE); 37 } 38 39 /** 40 * Access frame's data using a RenderTarget. 41 * This is a convenience method and is equivalent to calling {@code lockData} with an 42 * {@code accessFormat} of {@code ACCESS_RENDERTARGET}. 43 * 44 * @return The RenderTarget instance holding the Frame's data. 45 */ 46 public RenderTarget lockRenderTarget() { 47 return (RenderTarget)mBackingStore.lockData(MODE_WRITE, BackingStore.ACCESS_RENDERTARGET); 48 } 49 50 /** 51 * Assigns the pixel data of the specified bitmap. 52 * 53 * The RGBA pixel data will be extracted from the bitmap and assigned to the frame data. Note, 54 * that the colors are premultiplied with the alpha channel. If you wish to have 55 * non-premultiplied colors, you must pass the Frame through an 56 * {@code UnpremultiplyAlphaFilter}. 57 * 58 * @param bitmap The bitmap pixels to assign. 59 */ 60 public void setBitmap(Bitmap bitmap) { 61 bitmap = convertToFrameType(bitmap, mBackingStore.getFrameType()); 62 validateBitmapSize(bitmap, mBackingStore.getDimensions()); 63 Backing backing = mBackingStore.lockBacking(MODE_WRITE, BackingStore.ACCESS_BITMAP); 64 backing.setData(bitmap); 65 mBackingStore.unlock(); 66 } 67 68 /** 69 * Returns the RGBA image contents as a Bitmap instance. 70 * 71 * @return a Bitmap instance holding the RGBA Frame image content. 72 */ 73 public Bitmap toBitmap() { 74 Bitmap result = (Bitmap)mBackingStore.lockData(MODE_READ, BackingStore.ACCESS_BITMAP); 75 mBackingStore.unlock(); 76 return result; 77 } 78 79 /** 80 * Copies the image data from one frame to another. 81 * 82 * The source and target rectangles must be given in normalized coordinates, where 0,0 is the 83 * top-left of the image and 1,1 is the bottom-right. 84 * 85 * If the target rectangle is smaller than the target frame, the pixel values outside of the 86 * target rectangle are undefined. 87 * 88 * This method must be called within a Filter during execution. It supports both GL-enabled 89 * and GL-disabled run contexts. 90 * 91 * @param target The target frame to copy to. 92 * @param sourceRect The source rectangle in normalized coordinates. 93 * @param targetRect The target rectangle in normalized coordinates. 94 */ 95 public void copyToFrame(FrameImage2D target, RectF sourceRect, RectF targetRect) { 96 if (GraphRunner.current().isOpenGLSupported()) { 97 gpuImageCopy(this, target, sourceRect, targetRect); 98 } else { 99 cpuImageCopy(this, target, sourceRect, targetRect); 100 } 101 } 102 103 static FrameImage2D create(BackingStore backingStore) { 104 assertCanCreate(backingStore); 105 return new FrameImage2D(backingStore); 106 } 107 108 FrameImage2D(BackingStore backingStore) { 109 super(backingStore); 110 } 111 112 static void assertCanCreate(BackingStore backingStore) { 113 FrameBuffer2D.assertCanCreate(backingStore); 114 } 115 116 private static Bitmap convertToFrameType(Bitmap bitmap, FrameType type) { 117 Bitmap.Config config = bitmap.getConfig(); 118 Bitmap result = bitmap; 119 switch(type.getElementId()) { 120 case FrameType.ELEMENT_RGBA8888: 121 if (config != Bitmap.Config.ARGB_8888) { 122 result = bitmap.copy(Bitmap.Config.ARGB_8888, false); 123 if (result == null) { 124 throw new RuntimeException("Could not convert bitmap to frame-type " + 125 "RGBA8888!"); 126 } 127 } 128 break; 129 default: 130 throw new IllegalArgumentException("Unsupported frame type '" + type + "' for " + 131 "bitmap assignment!"); 132 } 133 return result; 134 } 135 136 private void validateBitmapSize(Bitmap bitmap, int[] dimensions) { 137 if (bitmap.getWidth() != dimensions[0] || bitmap.getHeight() != dimensions[1]) { 138 throw new IllegalArgumentException("Cannot assign bitmap of size " + bitmap.getWidth() 139 + "x" + bitmap.getHeight() + " to frame of size " + dimensions[0] + "x" 140 + dimensions[1] + "!"); 141 } 142 } 143 144 private static void gpuImageCopy( 145 FrameImage2D srcImage, FrameImage2D dstImage, RectF srcRect, RectF dstRect) { 146 ImageShader idShader = RenderTarget.currentTarget().getIdentityShader(); 147 // We briefly modify the shader 148 // TODO: Implement a safer way to save and restore a shared shader. 149 idShader.setSourceRect(srcRect); 150 idShader.setTargetRect(dstRect); 151 idShader.process(srcImage, dstImage); 152 // And reset it as others may use it as well 153 idShader.setSourceRect(0f, 0f, 1f, 1f); 154 idShader.setTargetRect(0f, 0f, 1f, 1f); 155 } 156 157 private static void cpuImageCopy( 158 FrameImage2D srcImage, FrameImage2D dstImage, RectF srcRect, RectF dstRect) { 159 // Convert rectangles to integer rectangles in image dimensions 160 Rect srcIRect = new Rect((int) srcRect.left * srcImage.getWidth(), 161 (int) srcRect.top * srcImage.getHeight(), 162 (int) srcRect.right * srcImage.getWidth(), 163 (int) srcRect.bottom * srcImage.getHeight()); 164 Rect dstIRect = new Rect((int) dstRect.left * srcImage.getWidth(), 165 (int) dstRect.top * srcImage.getHeight(), 166 (int) dstRect.right * srcImage.getWidth(), 167 (int) dstRect.bottom * srcImage.getHeight()); 168 169 // Create target canvas 170 Bitmap.Config config = Bitmap.Config.ARGB_8888; 171 Bitmap dstBitmap = Bitmap.createBitmap(dstImage.getWidth(), dstImage.getHeight(), config); 172 Canvas canvas = new Canvas(dstBitmap); 173 174 // Draw source bitmap into target canvas 175 Paint paint = new Paint(); 176 paint.setFilterBitmap(true); 177 Bitmap srcBitmap = srcImage.toBitmap(); 178 canvas.drawBitmap(srcBitmap, srcIRect, dstIRect, paint); 179 180 // Assign bitmap to output frame 181 dstImage.setBitmap(dstBitmap); 182 } 183 } 184 185