Home | History | Annotate | Download | only in core
      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 
     18 package android.filterfw.core;
     19 
     20 import android.filterfw.core.Frame;
     21 import android.filterfw.core.FrameFormat;
     22 import android.filterfw.core.FrameManager;
     23 import android.filterfw.format.ObjectFormat;
     24 import android.graphics.Bitmap;
     25 
     26 import java.io.InputStream;
     27 import java.io.IOException;
     28 import java.io.ObjectInputStream;
     29 import java.io.ObjectOutputStream;
     30 import java.io.OutputStream;
     31 import 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  */
     39 public 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