| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package androidx.media.filterfw; |
| |
| import android.graphics.Bitmap; |
| import android.graphics.Canvas; |
| import android.graphics.Paint; |
| import android.graphics.Rect; |
| import android.graphics.RectF; |
| import androidx.media.filterfw.BackingStore.Backing; |
| |
| public class FrameImage2D extends FrameBuffer2D { |
| |
| /** |
| * Access frame's data using a TextureSource. |
| * This is a convenience method and is equivalent to calling {@code lockData} with an |
| * {@code accessFormat} of {@code ACCESS_TEXTURE}. |
| * |
| * @return The TextureSource instance holding the Frame's data. |
| */ |
| public TextureSource lockTextureSource() { |
| return (TextureSource)mBackingStore.lockData(MODE_READ, BackingStore.ACCESS_TEXTURE); |
| } |
| |
| /** |
| * Access frame's data using a RenderTarget. |
| * This is a convenience method and is equivalent to calling {@code lockData} with an |
| * {@code accessFormat} of {@code ACCESS_RENDERTARGET}. |
| * |
| * @return The RenderTarget instance holding the Frame's data. |
| */ |
| public RenderTarget lockRenderTarget() { |
| return (RenderTarget)mBackingStore.lockData(MODE_WRITE, BackingStore.ACCESS_RENDERTARGET); |
| } |
| |
| /** |
| * Assigns the pixel data of the specified bitmap. |
| * |
| * The RGBA pixel data will be extracted from the bitmap and assigned to the frame data. Note, |
| * that the colors are premultiplied with the alpha channel. If you wish to have |
| * non-premultiplied colors, you must pass the Frame through an |
| * {@code UnpremultiplyAlphaFilter}. |
| * |
| * @param bitmap The bitmap pixels to assign. |
| */ |
| public void setBitmap(Bitmap bitmap) { |
| bitmap = convertToFrameType(bitmap, mBackingStore.getFrameType()); |
| validateBitmapSize(bitmap, mBackingStore.getDimensions()); |
| Backing backing = mBackingStore.lockBacking(MODE_WRITE, BackingStore.ACCESS_BITMAP); |
| backing.setData(bitmap); |
| mBackingStore.unlock(); |
| } |
| |
| /** |
| * Returns the RGBA image contents as a Bitmap instance. |
| * |
| * @return a Bitmap instance holding the RGBA Frame image content. |
| */ |
| public Bitmap toBitmap() { |
| Bitmap result = (Bitmap)mBackingStore.lockData(MODE_READ, BackingStore.ACCESS_BITMAP); |
| mBackingStore.unlock(); |
| return result; |
| } |
| |
| /** |
| * Copies the image data from one frame to another. |
| * |
| * The source and target rectangles must be given in normalized coordinates, where 0,0 is the |
| * top-left of the image and 1,1 is the bottom-right. |
| * |
| * If the target rectangle is smaller than the target frame, the pixel values outside of the |
| * target rectangle are undefined. |
| * |
| * This method must be called within a Filter during execution. It supports both GL-enabled |
| * and GL-disabled run contexts. |
| * |
| * @param target The target frame to copy to. |
| * @param sourceRect The source rectangle in normalized coordinates. |
| * @param targetRect The target rectangle in normalized coordinates. |
| */ |
| public void copyToFrame(FrameImage2D target, RectF sourceRect, RectF targetRect) { |
| if (GraphRunner.current().isOpenGLSupported()) { |
| gpuImageCopy(this, target, sourceRect, targetRect); |
| } else { |
| cpuImageCopy(this, target, sourceRect, targetRect); |
| } |
| } |
| |
| static FrameImage2D create(BackingStore backingStore) { |
| assertCanCreate(backingStore); |
| return new FrameImage2D(backingStore); |
| } |
| |
| FrameImage2D(BackingStore backingStore) { |
| super(backingStore); |
| } |
| |
| static void assertCanCreate(BackingStore backingStore) { |
| FrameBuffer2D.assertCanCreate(backingStore); |
| } |
| |
| private static Bitmap convertToFrameType(Bitmap bitmap, FrameType type) { |
| Bitmap.Config config = bitmap.getConfig(); |
| Bitmap result = bitmap; |
| switch(type.getElementId()) { |
| case FrameType.ELEMENT_RGBA8888: |
| if (config != Bitmap.Config.ARGB_8888) { |
| result = bitmap.copy(Bitmap.Config.ARGB_8888, false); |
| if (result == null) { |
| throw new RuntimeException("Could not convert bitmap to frame-type " + |
| "RGBA8888!"); |
| } |
| } |
| break; |
| default: |
| throw new IllegalArgumentException("Unsupported frame type '" + type + "' for " + |
| "bitmap assignment!"); |
| } |
| return result; |
| } |
| |
| private void validateBitmapSize(Bitmap bitmap, int[] dimensions) { |
| if (bitmap.getWidth() != dimensions[0] || bitmap.getHeight() != dimensions[1]) { |
| throw new IllegalArgumentException("Cannot assign bitmap of size " + bitmap.getWidth() |
| + "x" + bitmap.getHeight() + " to frame of size " + dimensions[0] + "x" |
| + dimensions[1] + "!"); |
| } |
| } |
| |
| private static void gpuImageCopy( |
| FrameImage2D srcImage, FrameImage2D dstImage, RectF srcRect, RectF dstRect) { |
| ImageShader idShader = RenderTarget.currentTarget().getIdentityShader(); |
| // We briefly modify the shader |
| // TODO: Implement a safer way to save and restore a shared shader. |
| idShader.setSourceRect(srcRect); |
| idShader.setTargetRect(dstRect); |
| idShader.process(srcImage, dstImage); |
| // And reset it as others may use it as well |
| idShader.setSourceRect(0f, 0f, 1f, 1f); |
| idShader.setTargetRect(0f, 0f, 1f, 1f); |
| } |
| |
| private static void cpuImageCopy( |
| FrameImage2D srcImage, FrameImage2D dstImage, RectF srcRect, RectF dstRect) { |
| // Convert rectangles to integer rectangles in image dimensions |
| Rect srcIRect = new Rect((int) srcRect.left * srcImage.getWidth(), |
| (int) srcRect.top * srcImage.getHeight(), |
| (int) srcRect.right * srcImage.getWidth(), |
| (int) srcRect.bottom * srcImage.getHeight()); |
| Rect dstIRect = new Rect((int) dstRect.left * srcImage.getWidth(), |
| (int) dstRect.top * srcImage.getHeight(), |
| (int) dstRect.right * srcImage.getWidth(), |
| (int) dstRect.bottom * srcImage.getHeight()); |
| |
| // Create target canvas |
| Bitmap.Config config = Bitmap.Config.ARGB_8888; |
| Bitmap dstBitmap = Bitmap.createBitmap(dstImage.getWidth(), dstImage.getHeight(), config); |
| Canvas canvas = new Canvas(dstBitmap); |
| |
| // Draw source bitmap into target canvas |
| Paint paint = new Paint(); |
| paint.setFilterBitmap(true); |
| Bitmap srcBitmap = srcImage.toBitmap(); |
| canvas.drawBitmap(srcBitmap, srcIRect, dstIRect, paint); |
| |
| // Assign bitmap to output frame |
| dstImage.setBitmap(dstBitmap); |
| } |
| } |
| |