diff options
Diffstat (limited to 'media/mca/filterfw/java/android/filterfw/core/SerializedFrame.java')
-rw-r--r-- | media/mca/filterfw/java/android/filterfw/core/SerializedFrame.java | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/media/mca/filterfw/java/android/filterfw/core/SerializedFrame.java b/media/mca/filterfw/java/android/filterfw/core/SerializedFrame.java new file mode 100644 index 0000000..f493fd2 --- /dev/null +++ b/media/mca/filterfw/java/android/filterfw/core/SerializedFrame.java @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.filterfw.core; + +import android.filterfw.core.Frame; +import android.filterfw.core.FrameFormat; +import android.filterfw.core.FrameManager; +import android.filterfw.core.NativeBuffer; +import android.filterfw.format.ObjectFormat; +import android.graphics.Bitmap; + +import java.io.InputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OptionalDataException; +import java.io.OutputStream; +import java.io.StreamCorruptedException; +import java.lang.reflect.Constructor; +import java.nio.ByteBuffer; + +/** + * A frame that serializes any assigned values. Such a frame is used when passing data objects + * between threads. + * + * @hide + */ +public class SerializedFrame extends Frame { + + /** + * The initial capacity of the serialized data stream. + */ + private final static int INITIAL_CAPACITY = 64; + + /** + * The internal data streams. + */ + private DirectByteOutputStream mByteOutputStream; + private ObjectOutputStream mObjectOut; + + /** + * An unsynchronized output stream that writes data to an accessible byte array. Callers are + * responsible for synchronization. This is more efficient than a ByteArrayOutputStream, as + * there are no array copies or synchronization involved to read back written data. + */ + private class DirectByteOutputStream extends OutputStream { + private byte[] mBuffer = null; + private int mOffset = 0; + private int mDataOffset = 0; + + public DirectByteOutputStream(int size) { + mBuffer = new byte[size]; + } + + private final void ensureFit(int bytesToWrite) { + if (mOffset + bytesToWrite > mBuffer.length) { + byte[] oldBuffer = mBuffer; + mBuffer = new byte[Math.max(mOffset + bytesToWrite, mBuffer.length * 2)]; + System.arraycopy(oldBuffer, 0, mBuffer, 0, mOffset); + oldBuffer = null; + } + } + + public final void markHeaderEnd() { + mDataOffset = mOffset; + } + + public final int getSize() { + return mOffset; + } + + public byte[] getByteArray() { + return mBuffer; + } + + @Override + public final void write(byte b[]) { + write(b, 0, b.length); + } + + @Override + public final void write(byte b[], int off, int len) { + ensureFit(len); + System.arraycopy(b, off, mBuffer, mOffset, len); + mOffset += len; + } + + @Override + public final void write(int b) { + ensureFit(1); + mBuffer[mOffset++] = (byte)b; + } + + public final void reset() { + mOffset = mDataOffset; + } + + public final DirectByteInputStream getInputStream() { + return new DirectByteInputStream(mBuffer, mOffset); + } + } + + /** + * An unsynchronized input stream that reads data directly from a provided byte array. Callers + * are responsible for synchronization and ensuring that the byte buffer is valid. + */ + private class DirectByteInputStream extends InputStream { + + private byte[] mBuffer; + private int mPos = 0; + private int mSize; + + public DirectByteInputStream(byte[] buffer, int size) { + mBuffer = buffer; + mSize = size; + } + + @Override + public final int available() { + return mSize - mPos; + } + + @Override + public final int read() { + return (mPos < mSize) ? (mBuffer[mPos++] & 0xFF) : -1; + } + + @Override + public final int read(byte[] b, int off, int len) { + if (mPos >= mSize) { + return -1; + } + if ((mPos + len) > mSize) { + len = mSize - mPos; + } + System.arraycopy(mBuffer, mPos, b, off, len); + mPos += len; + return len; + } + + @Override + public final long skip(long n) { + if ((mPos + n) > mSize) { + n = mSize - mPos; + } + if (n < 0) { + return 0; + } + mPos += n; + return n; + } + } + + SerializedFrame(FrameFormat format, FrameManager frameManager) { + super(format, frameManager); + setReusable(false); + + // Setup streams + try { + mByteOutputStream = new DirectByteOutputStream(INITIAL_CAPACITY); + mObjectOut = new ObjectOutputStream(mByteOutputStream); + mByteOutputStream.markHeaderEnd(); + } catch (IOException e) { + throw new RuntimeException("Could not create serialization streams for " + + "SerializedFrame!", e); + } + } + + static SerializedFrame wrapObject(Object object, FrameManager frameManager) { + FrameFormat format = ObjectFormat.fromObject(object, FrameFormat.TARGET_SIMPLE); + SerializedFrame result = new SerializedFrame(format, frameManager); + result.setObjectValue(object); + return result; + } + + @Override + protected boolean hasNativeAllocation() { + return false; + } + + @Override + protected void releaseNativeAllocation() { + } + + @Override + public Object getObjectValue() { + return deserializeObjectValue(); + } + + @Override + public void setInts(int[] ints) { + assertFrameMutable(); + setGenericObjectValue(ints); + } + + @Override + public int[] getInts() { + Object result = deserializeObjectValue(); + return (result instanceof int[]) ? (int[])result : null; + } + + @Override + public void setFloats(float[] floats) { + assertFrameMutable(); + setGenericObjectValue(floats); + } + + @Override + public float[] getFloats() { + Object result = deserializeObjectValue(); + return (result instanceof float[]) ? (float[])result : null; + } + + @Override + public void setData(ByteBuffer buffer, int offset, int length) { + assertFrameMutable(); + setGenericObjectValue(ByteBuffer.wrap(buffer.array(), offset, length)); + } + + @Override + public ByteBuffer getData() { + Object result = deserializeObjectValue(); + return (result instanceof ByteBuffer) ? (ByteBuffer)result : null; + } + + @Override + public void setBitmap(Bitmap bitmap) { + assertFrameMutable(); + setGenericObjectValue(bitmap); + } + + @Override + public Bitmap getBitmap() { + Object result = deserializeObjectValue(); + return (result instanceof Bitmap) ? (Bitmap)result : null; + } + + @Override + protected void setGenericObjectValue(Object object) { + serializeObjectValue(object); + } + + private final void serializeObjectValue(Object object) { + try { + mByteOutputStream.reset(); + mObjectOut.writeObject(object); + mObjectOut.flush(); + mObjectOut.close(); + } catch (IOException e) { + throw new RuntimeException("Could not serialize object " + object + " in " + + this + "!", e); + } + } + + private final Object deserializeObjectValue() { + try { + InputStream inputStream = mByteOutputStream.getInputStream(); + ObjectInputStream objectStream = new ObjectInputStream(inputStream); + return objectStream.readObject(); + } catch (IOException e) { + throw new RuntimeException("Could not deserialize object in " + this + "!", e); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Unable to deserialize object of unknown class in " + + this + "!", e); + } + } + + @Override + public String toString() { + return "SerializedFrame (" + getFormat() + ")"; + } +} |