SerializedFrame.java revision 6090995951c6e2e4dcf38102f01793f8a94166e1
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.format.ObjectFormat; 24import android.graphics.Bitmap; 25 26import java.io.InputStream; 27import java.io.IOException; 28import java.io.ObjectInputStream; 29import java.io.ObjectOutputStream; 30import java.io.OutputStream; 31import java.nio.ByteBuffer; 32 33/** 34 * A frame that serializes any assigned values. Such a frame is used when passing data objects 35 * between threads. 36 * 37 * @hide 38 */ 39public class SerializedFrame extends Frame { 40 41 /** 42 * The initial capacity of the serialized data stream. 43 */ 44 private final static int INITIAL_CAPACITY = 64; 45 46 /** 47 * The internal data streams. 48 */ 49 private DirectByteOutputStream mByteOutputStream; 50 private ObjectOutputStream mObjectOut; 51 52 /** 53 * An unsynchronized output stream that writes data to an accessible byte array. Callers are 54 * responsible for synchronization. This is more efficient than a ByteArrayOutputStream, as 55 * there are no array copies or synchronization involved to read back written data. 56 */ 57 private class DirectByteOutputStream extends OutputStream { 58 private byte[] mBuffer = null; 59 private int mOffset = 0; 60 private int mDataOffset = 0; 61 62 public DirectByteOutputStream(int size) { 63 mBuffer = new byte[size]; 64 } 65 66 private final void ensureFit(int bytesToWrite) { 67 if (mOffset + bytesToWrite > mBuffer.length) { 68 byte[] oldBuffer = mBuffer; 69 mBuffer = new byte[Math.max(mOffset + bytesToWrite, mBuffer.length * 2)]; 70 System.arraycopy(oldBuffer, 0, mBuffer, 0, mOffset); 71 oldBuffer = null; 72 } 73 } 74 75 public final void markHeaderEnd() { 76 mDataOffset = mOffset; 77 } 78 79 public final int getSize() { 80 return mOffset; 81 } 82 83 public byte[] getByteArray() { 84 return mBuffer; 85 } 86 87 @Override 88 public final void write(byte b[]) { 89 write(b, 0, b.length); 90 } 91 92 @Override 93 public final void write(byte b[], int off, int len) { 94 ensureFit(len); 95 System.arraycopy(b, off, mBuffer, mOffset, len); 96 mOffset += len; 97 } 98 99 @Override 100 public final void write(int b) { 101 ensureFit(1); 102 mBuffer[mOffset++] = (byte)b; 103 } 104 105 public final void reset() { 106 mOffset = mDataOffset; 107 } 108 109 public final DirectByteInputStream getInputStream() { 110 return new DirectByteInputStream(mBuffer, mOffset); 111 } 112 } 113 114 /** 115 * An unsynchronized input stream that reads data directly from a provided byte array. Callers 116 * are responsible for synchronization and ensuring that the byte buffer is valid. 117 */ 118 private class DirectByteInputStream extends InputStream { 119 120 private byte[] mBuffer; 121 private int mPos = 0; 122 private int mSize; 123 124 public DirectByteInputStream(byte[] buffer, int size) { 125 mBuffer = buffer; 126 mSize = size; 127 } 128 129 @Override 130 public final int available() { 131 return mSize - mPos; 132 } 133 134 @Override 135 public final int read() { 136 return (mPos < mSize) ? (mBuffer[mPos++] & 0xFF) : -1; 137 } 138 139 @Override 140 public final int read(byte[] b, int off, int len) { 141 if (mPos >= mSize) { 142 return -1; 143 } 144 if ((mPos + len) > mSize) { 145 len = mSize - mPos; 146 } 147 System.arraycopy(mBuffer, mPos, b, off, len); 148 mPos += len; 149 return len; 150 } 151 152 @Override 153 public final long skip(long n) { 154 if ((mPos + n) > mSize) { 155 n = mSize - mPos; 156 } 157 if (n < 0) { 158 return 0; 159 } 160 mPos += n; 161 return n; 162 } 163 } 164 165 SerializedFrame(FrameFormat format, FrameManager frameManager) { 166 super(format, frameManager); 167 setReusable(false); 168 169 // Setup streams 170 try { 171 mByteOutputStream = new DirectByteOutputStream(INITIAL_CAPACITY); 172 mObjectOut = new ObjectOutputStream(mByteOutputStream); 173 mByteOutputStream.markHeaderEnd(); 174 } catch (IOException e) { 175 throw new RuntimeException("Could not create serialization streams for " 176 + "SerializedFrame!", e); 177 } 178 } 179 180 static SerializedFrame wrapObject(Object object, FrameManager frameManager) { 181 FrameFormat format = ObjectFormat.fromObject(object, FrameFormat.TARGET_SIMPLE); 182 SerializedFrame result = new SerializedFrame(format, frameManager); 183 result.setObjectValue(object); 184 return result; 185 } 186 187 @Override 188 protected boolean hasNativeAllocation() { 189 return false; 190 } 191 192 @Override 193 protected void releaseNativeAllocation() { 194 } 195 196 @Override 197 public Object getObjectValue() { 198 return deserializeObjectValue(); 199 } 200 201 @Override 202 public void setInts(int[] ints) { 203 assertFrameMutable(); 204 setGenericObjectValue(ints); 205 } 206 207 @Override 208 public int[] getInts() { 209 Object result = deserializeObjectValue(); 210 return (result instanceof int[]) ? (int[])result : null; 211 } 212 213 @Override 214 public void setFloats(float[] floats) { 215 assertFrameMutable(); 216 setGenericObjectValue(floats); 217 } 218 219 @Override 220 public float[] getFloats() { 221 Object result = deserializeObjectValue(); 222 return (result instanceof float[]) ? (float[])result : null; 223 } 224 225 @Override 226 public void setData(ByteBuffer buffer, int offset, int length) { 227 assertFrameMutable(); 228 setGenericObjectValue(ByteBuffer.wrap(buffer.array(), offset, length)); 229 } 230 231 @Override 232 public ByteBuffer getData() { 233 Object result = deserializeObjectValue(); 234 return (result instanceof ByteBuffer) ? (ByteBuffer)result : null; 235 } 236 237 @Override 238 public void setBitmap(Bitmap bitmap) { 239 assertFrameMutable(); 240 setGenericObjectValue(bitmap); 241 } 242 243 @Override 244 public Bitmap getBitmap() { 245 Object result = deserializeObjectValue(); 246 return (result instanceof Bitmap) ? (Bitmap)result : null; 247 } 248 249 @Override 250 protected void setGenericObjectValue(Object object) { 251 serializeObjectValue(object); 252 } 253 254 private final void serializeObjectValue(Object object) { 255 try { 256 mByteOutputStream.reset(); 257 mObjectOut.writeObject(object); 258 mObjectOut.flush(); 259 mObjectOut.close(); 260 } catch (IOException e) { 261 throw new RuntimeException("Could not serialize object " + object + " in " 262 + this + "!", e); 263 } 264 } 265 266 private final Object deserializeObjectValue() { 267 try { 268 InputStream inputStream = mByteOutputStream.getInputStream(); 269 ObjectInputStream objectStream = new ObjectInputStream(inputStream); 270 return objectStream.readObject(); 271 } catch (IOException e) { 272 throw new RuntimeException("Could not deserialize object in " + this + "!", e); 273 } catch (ClassNotFoundException e) { 274 throw new RuntimeException("Unable to deserialize object of unknown class in " 275 + this + "!", e); 276 } 277 } 278 279 @Override 280 public String toString() { 281 return "SerializedFrame (" + getFormat() + ")"; 282 } 283} 284