NativeFrame.java revision a3bfbe5389c6146abe318a7add3fa688d69bc01b
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 18package android.filterfw.core; 19 20import android.filterfw.core.Frame; 21import android.filterfw.core.FrameFormat; 22import android.filterfw.core.FrameManager; 23import android.filterfw.core.GLFrame; 24import android.filterfw.core.NativeBuffer; 25import android.graphics.Bitmap; 26 27import java.nio.ByteBuffer; 28 29/** 30 * @hide 31 */ 32public class NativeFrame extends Frame { 33 34 private int nativeFrameId; 35 36 NativeFrame(FrameFormat format, FrameManager frameManager, boolean isEmpty) { 37 super(format, frameManager); 38 int capacity = format.getSize(); 39 if (isEmpty && capacity != 0) { 40 throw new IllegalArgumentException( 41 "Initializing empty native frame with non-zero size! You must not specify any " + 42 "dimensions when allocating an empty frame!"); 43 } else if (!isEmpty && capacity <= 0) { 44 throw new IllegalArgumentException( 45 "Initializing non-empty native frame with no size specified! Did you forget " + 46 "to set the dimensions?"); 47 } else { 48 allocate(capacity); 49 } 50 setReusable(!isEmpty); 51 } 52 53 @Override 54 void dealloc() { 55 deallocate(); 56 } 57 58 @Override 59 public int getCapacity() { 60 return getNativeCapacity(); 61 } 62 63 @Override 64 public Object getObjectValue() { 65 // If this is not a structured frame, return our data 66 if (getFormat().getBaseType() != FrameFormat.TYPE_OBJECT) { 67 return getData(); 68 } 69 70 // Get the structure class 71 Class structClass = getFormat().getObjectClass(); 72 if (structClass == null) { 73 throw new RuntimeException("Attempting to get object data from frame that does " + 74 "not specify a structure object class!"); 75 } 76 77 // Make sure it is a NativeBuffer subclass 78 if (!NativeBuffer.class.isAssignableFrom(structClass)) { 79 throw new RuntimeException("NativeFrame object class must be a subclass of " + 80 "NativeBuffer!"); 81 } 82 83 // Instantiate a new empty instance of this class 84 NativeBuffer structData = null; 85 try { 86 structData = (NativeBuffer)structClass.newInstance(); 87 } catch (Exception e) { 88 throw new RuntimeException("Could not instantiate new structure instance of type '" + 89 structClass + "'!"); 90 } 91 92 // Wrap it around our data 93 if (!getNativeBuffer(structData)) { 94 throw new RuntimeException("Could not get the native structured data for frame!"); 95 } 96 97 // Attach this frame to it, so that we do not get deallocated while the NativeBuffer is 98 // accessing our data. 99 structData.attachToFrame(this); 100 101 return structData; 102 } 103 104 @Override 105 public void setInts(int[] ints) { 106 assertFrameMutable(); 107 if (ints.length * nativeIntSize() > getFormat().getSize()) { 108 throw new RuntimeException( 109 "NativeFrame cannot hold " + ints.length + " integers. (Can only hold " + 110 (getFormat().getSize() / nativeIntSize()) + " integers)."); 111 } else if (!setNativeInts(ints)) { 112 throw new RuntimeException("Could not set int values for native frame!"); 113 } 114 } 115 116 @Override 117 public int[] getInts() { 118 return getNativeInts(getFormat().getSize()); 119 } 120 121 @Override 122 public void setFloats(float[] floats) { 123 assertFrameMutable(); 124 if (floats.length * nativeFloatSize() > getFormat().getSize()) { 125 throw new RuntimeException( 126 "NativeFrame cannot hold " + floats.length + " floats. (Can only hold " + 127 (getFormat().getSize() / nativeFloatSize()) + " floats)."); 128 } else if (!setNativeFloats(floats)) { 129 throw new RuntimeException("Could not set int values for native frame!"); 130 } 131 } 132 133 @Override 134 public float[] getFloats() { 135 return getNativeFloats(getFormat().getSize()); 136 } 137 138 // TODO: This function may be a bit confusing: Is the offset the target or source offset? Maybe 139 // we should allow specifying both? (May be difficult for other frame types). 140 @Override 141 public void setData(ByteBuffer buffer, int offset, int length) { 142 assertFrameMutable(); 143 byte[] bytes = buffer.array(); 144 if ((length + offset) > buffer.limit()) { 145 throw new RuntimeException("Offset and length exceed buffer size in native setData: " + 146 (length + offset) + " bytes given, but only " + buffer.limit() + 147 " bytes available!"); 148 } else if (getFormat().getSize() != length) { 149 throw new RuntimeException("Data size in setData does not match native frame size: " + 150 "Frame size is " + getFormat().getSize() + " bytes, but " + 151 length + " bytes given!"); 152 } else if (!setNativeData(bytes, offset, length)) { 153 throw new RuntimeException("Could not set native frame data!"); 154 } 155 } 156 157 @Override 158 public ByteBuffer getData() { 159 return ByteBuffer.wrap(getNativeData(getFormat().getSize())); 160 } 161 162 @Override 163 public void setBitmap(Bitmap bitmap) { 164 assertFrameMutable(); 165 if (getFormat().getNumberOfDimensions() != 2) { 166 throw new RuntimeException("Attempting to set Bitmap for non 2-dimensional native frame!"); 167 } else if (getFormat().getWidth() != bitmap.getWidth() || 168 getFormat().getHeight() != bitmap.getHeight()) { 169 throw new RuntimeException("Bitmap dimensions do not match native frame dimensions!"); 170 } else { 171 Bitmap rgbaBitmap = convertBitmapToRGBA(bitmap); 172 if (!setNativeBitmap(rgbaBitmap, rgbaBitmap.getByteCount())) { 173 throw new RuntimeException("Could not set native frame bitmap data!"); 174 } 175 } 176 } 177 178 @Override 179 public Bitmap getBitmap() { 180 if (getFormat().getNumberOfDimensions() != 2) { 181 throw new RuntimeException("Attempting to get Bitmap for non 2-dimensional native frame!"); 182 } 183 Bitmap result = Bitmap.createBitmap(getFormat().getWidth(), 184 getFormat().getHeight(), 185 Bitmap.Config.ARGB_8888); 186 if (!getNativeBitmap(result)) { 187 throw new RuntimeException("Could not get bitmap data from native frame!"); 188 } 189 return result; 190 } 191 192 @Override 193 public void setDataFromFrame(Frame frame) { 194 // Make sure frame fits 195 if (getFormat().getSize() < frame.getFormat().getSize()) { 196 throw new RuntimeException( 197 "Attempting to assign frame of size " + frame.getFormat().getSize() + " to " + 198 "smaller native frame of size " + getFormat().getSize() + "!"); 199 } 200 201 // Invoke optimized implementations if possible 202 if (frame instanceof NativeFrame) { 203 nativeCopyFromNative((NativeFrame)frame); 204 } else if (frame instanceof GLFrame) { 205 nativeCopyFromGL((GLFrame)frame); 206 } else if (frame instanceof JavaFrame) { 207 setObjectValue(frame.getObjectValue()); 208 } else { 209 super.setDataFromFrame(frame); 210 } 211 } 212 213 @Override 214 public String toString() { 215 return "NativeFrame (" + getFormat() + ") with native buffer of size " + getCapacity(); 216 } 217 218 static { 219 System.loadLibrary("filterfw"); 220 } 221 222 private native boolean allocate(int capacity); 223 224 private native boolean deallocate(); 225 226 private native int getNativeCapacity(); 227 228 private static native int nativeIntSize(); 229 230 private static native int nativeFloatSize(); 231 232 private native boolean setNativeData(byte[] data, int offset, int length); 233 234 private native byte[] getNativeData(int byteCount); 235 236 private native boolean getNativeBuffer(NativeBuffer buffer); 237 238 private native boolean setNativeInts(int[] ints); 239 240 private native boolean setNativeFloats(float[] floats); 241 242 private native int[] getNativeInts(int byteCount); 243 244 private native float[] getNativeFloats(int byteCount); 245 246 private native boolean setNativeBitmap(Bitmap bitmap, int size); 247 248 private native boolean getNativeBitmap(Bitmap bitmap); 249 250 private native boolean nativeCopyFromNative(NativeFrame frame); 251 252 private native boolean nativeCopyFromGL(GLFrame frame); 253} 254