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