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