Home | History | Annotate | Download | only in jpegstream
      1 /*
      2  * Copyright (C) 2013 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 package com.android.gallery3d.jpegstream;
     18 
     19 import android.graphics.Point;
     20 
     21 import java.io.FilterInputStream;
     22 import java.io.IOException;
     23 import java.io.InputStream;
     24 
     25 public class JPEGInputStream extends FilterInputStream {
     26     private long JNIPointer = 0; // Used by JNI code. Don't touch.
     27 
     28     private boolean mValidConfig = false;
     29     private boolean mConfigChanged = false;
     30     private int mFormat = -1;
     31     private byte[] mTmpBuffer = new byte[1];
     32     private int mWidth = 0;
     33     private int mHeight = 0;
     34 
     35     public JPEGInputStream(InputStream in) {
     36         super(in);
     37     }
     38 
     39     public JPEGInputStream(InputStream in, int format) {
     40         super(in);
     41         setConfig(format);
     42     }
     43 
     44     public boolean setConfig(int format) {
     45         // Make sure format is valid
     46         switch (format) {
     47             case JpegConfig.FORMAT_GRAYSCALE:
     48             case JpegConfig.FORMAT_RGB:
     49             case JpegConfig.FORMAT_ABGR:
     50             case JpegConfig.FORMAT_RGBA:
     51                 break;
     52             default:
     53                 return false;
     54         }
     55         mFormat = format;
     56         mValidConfig = true;
     57         mConfigChanged = true;
     58         return true;
     59     }
     60 
     61     public Point getDimensions() throws IOException {
     62         if (mValidConfig) {
     63             applyConfigChange();
     64             return new Point(mWidth, mHeight);
     65         }
     66         return null;
     67     }
     68 
     69     @Override
     70     public int available() {
     71         return 0; // TODO
     72     }
     73 
     74     @Override
     75     public void close() throws IOException {
     76         cleanup();
     77         super.close();
     78     }
     79 
     80     @Override
     81     public synchronized void mark(int readlimit) {
     82         // Do nothing
     83     }
     84 
     85     @Override
     86     public boolean markSupported() {
     87         return false;
     88     }
     89 
     90     @Override
     91     public int read() throws IOException {
     92         read(mTmpBuffer, 0, 1);
     93         return 0xFF & mTmpBuffer[0];
     94     }
     95 
     96     @Override
     97     public int read(byte[] buffer) throws IOException {
     98         return read(buffer, 0, buffer.length);
     99     }
    100 
    101     @Override
    102     public int read(byte[] buffer, int offset, int count) throws IOException {
    103         if (offset < 0 || count < 0 || (offset + count) > buffer.length) {
    104             throw new ArrayIndexOutOfBoundsException(String.format(
    105                     " buffer length %d, offset %d, length %d",
    106                     buffer.length, offset, count));
    107         }
    108         if (!mValidConfig) {
    109             return 0;
    110         }
    111         applyConfigChange();
    112         int flag = JpegConfig.J_ERROR_FATAL;
    113         try {
    114             flag = readDecodedBytes(buffer, offset, count);
    115         } finally {
    116             if (flag < 0) {
    117                 cleanup();
    118             }
    119         }
    120         if (flag < 0) {
    121             switch (flag) {
    122                 case JpegConfig.J_DONE:
    123                     return -1; // Returns -1 after reading EOS.
    124                 default:
    125                     throw new IOException("Error reading jpeg stream");
    126             }
    127         }
    128         return flag;
    129     }
    130 
    131     @Override
    132     public synchronized void reset() throws IOException {
    133         throw new IOException("Reset not supported.");
    134     }
    135 
    136     @Override
    137     public long skip(long byteCount) throws IOException {
    138         if (byteCount <= 0) {
    139             return 0;
    140         }
    141         // Shorten skip to a reasonable amount
    142         int flag = skipDecodedBytes((int) (0x7FFFFFFF & byteCount));
    143         if (flag < 0) {
    144             switch (flag) {
    145                 case JpegConfig.J_DONE:
    146                     return 0; // Returns 0 after reading EOS.
    147                 default:
    148                     throw new IOException("Error skipping jpeg stream");
    149             }
    150         }
    151         return flag;
    152     }
    153 
    154     @Override
    155     protected void finalize() throws Throwable {
    156         try {
    157             cleanup();
    158         } finally {
    159             super.finalize();
    160         }
    161     }
    162 
    163     private void applyConfigChange() throws IOException {
    164         if (mConfigChanged) {
    165             cleanup();
    166             Point dimens = new Point(0, 0);
    167             int flag = setup(dimens, in, mFormat);
    168             switch(flag) {
    169                 case JpegConfig.J_SUCCESS:
    170                     break; // allow setup to continue
    171                 case JpegConfig.J_ERROR_BAD_ARGS:
    172                     throw new IllegalArgumentException("Bad arguments to read");
    173                 default:
    174                     throw new IOException("Error to reading jpeg headers.");
    175             }
    176             mWidth = dimens.x;
    177             mHeight = dimens.y;
    178             mConfigChanged = false;
    179         }
    180     }
    181 
    182     native private int setup(Point dimens, InputStream in, int format);
    183 
    184     native private void cleanup();
    185 
    186     native private int readDecodedBytes( byte[] inBuffer, int offset, int inCount);
    187 
    188     native private int skipDecodedBytes(int bytes);
    189 
    190     static {
    191         System.loadLibrary("jni_jpegstream");
    192     }
    193 }
    194