Home | History | Annotate | Download | only in filterfw
      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