1/* 2 * Copyright (C) 2014 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 17package com.android.camera.data; 18 19import android.graphics.Bitmap; 20import android.graphics.BitmapFactory; 21import android.graphics.Matrix; 22import android.graphics.Point; 23import android.media.MediaMetadataRetriever; 24 25import com.android.camera.debug.Log; 26 27import java.io.InputStream; 28 29import javax.microedition.khronos.opengles.GL11; 30 31/** 32 * An utility class for data in content provider. 33 */ 34public class FilmstripItemUtils { 35 36 private static final Log.Tag TAG = new Log.Tag("LocalDataUtil"); 37 38 /** 39 * @param mimeType The MIME type to check. 40 * @return Whether the MIME is a video type. 41 */ 42 public static boolean isMimeTypeVideo(String mimeType) { 43 return mimeType != null && mimeType.startsWith("video/"); 44 } 45 46 /** 47 * Checks whether the MIME type represents an image media item. 48 * 49 * @param mimeType The MIME type to check. 50 * @return Whether the MIME is a image type. 51 */ 52 public static boolean isMimeTypeImage(String mimeType) { 53 return mimeType != null && mimeType.startsWith("image/"); 54 } 55 56 57 /** 58 * Decodes the dimension of a bitmap. 59 * 60 * @param is An input stream with the data of the bitmap. 61 * @return The decoded width/height is stored in Point.x/Point.y 62 * respectively. 63 */ 64 public static Point decodeBitmapDimension(InputStream is) { 65 Point size = null; 66 BitmapFactory.Options justBoundsOpts = new BitmapFactory.Options(); 67 justBoundsOpts.inJustDecodeBounds = true; 68 BitmapFactory.decodeStream(is, null, justBoundsOpts); 69 if (justBoundsOpts.outWidth > 0 && justBoundsOpts.outHeight > 0) { 70 size = new Point(justBoundsOpts.outWidth, justBoundsOpts.outHeight); 71 } else { 72 Log.e(TAG, "Bitmap dimension decoding failed"); 73 } 74 return size; 75 } 76 77 /** 78 * Load the thumbnail of an image from an {@link java.io.InputStream}. 79 * 80 * @param stream The input stream of the image. 81 * @param imageWidth Image width. 82 * @param imageHeight Image height. 83 * @param widthBound The bound of the width of the decoded image. 84 * @param heightBound The bound of the height of the decoded image. 85 * @param orientation The orientation of the image. The image will be rotated 86 * clockwise in degrees. 87 * @param maximumPixels The bound for the number of pixels of the decoded image. 88 * @return {@code null} if the decoding failed. 89 */ 90 public static Bitmap loadImageThumbnailFromStream(InputStream stream, int imageWidth, 91 int imageHeight, int widthBound, int heightBound, int orientation, 92 int maximumPixels) { 93 94 /** 32K buffer. */ 95 byte[] decodeBuffer = new byte[32 * 1024]; 96 97 if (orientation % 180 != 0) { 98 int dummy = imageHeight; 99 imageHeight = imageWidth; 100 imageWidth = dummy; 101 } 102 103 // Generate Bitmap of maximum size that fits into widthBound x heightBound. 104 // Algorithm: start with full size and step down in powers of 2. 105 int targetWidth = imageWidth; 106 int targetHeight = imageHeight; 107 int sampleSize = 1; 108 while (targetHeight > heightBound || targetWidth > widthBound || 109 targetHeight > GL11.GL_MAX_TEXTURE_SIZE || targetWidth > GL11.GL_MAX_TEXTURE_SIZE || 110 targetHeight * targetWidth > maximumPixels) { 111 sampleSize <<= 1; 112 targetWidth = imageWidth / sampleSize; 113 targetHeight = imageWidth / sampleSize; 114 } 115 116 // For large (> MAXIMUM_TEXTURE_SIZE) high aspect ratio (panorama) 117 // Bitmap requests: 118 // Step 1: ask for double size. 119 // Step 2: scale maximum edge down to MAXIMUM_TEXTURE_SIZE. 120 // 121 // Here's the step 1: double size. 122 if ((heightBound > GL11.GL_MAX_TEXTURE_SIZE || widthBound > GL11.GL_MAX_TEXTURE_SIZE) && 123 targetWidth * targetHeight < maximumPixels / 4 && sampleSize > 1) { 124 sampleSize >>= 2; 125 } 126 127 BitmapFactory.Options opts = new BitmapFactory.Options(); 128 opts.inSampleSize = sampleSize; 129 opts.inTempStorage = decodeBuffer; 130 Bitmap b = BitmapFactory.decodeStream(stream, null, opts); 131 132 if (b == null) { 133 return null; 134 } 135 136 // Step 2: scale maximum edge down to maximum texture size. 137 // If Bitmap maximum edge > MAXIMUM_TEXTURE_SIZE, which can happen for panoramas, 138 // scale to fit in MAXIMUM_TEXTURE_SIZE. 139 if (b.getWidth() > GL11.GL_MAX_TEXTURE_SIZE || b.getHeight() > 140 GL11.GL_MAX_TEXTURE_SIZE) { 141 int maxEdge = Math.max(b.getWidth(), b.getHeight()); 142 b = Bitmap.createScaledBitmap(b, b.getWidth() * GL11.GL_MAX_TEXTURE_SIZE / maxEdge, 143 b.getHeight() * GL11.GL_MAX_TEXTURE_SIZE / maxEdge, false); 144 } 145 146 // Not called often because most modes save image data non-rotated. 147 if (orientation != 0 && b != null) { 148 Matrix m = new Matrix(); 149 m.setRotate(orientation); 150 b = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), m, false); 151 } 152 153 return b; 154 } 155 156 /** 157 * Loads the thumbnail of a video. 158 * 159 * @param path The path to the video file. 160 * @return {@code null} if the loading failed. 161 */ 162 public static Bitmap loadVideoThumbnail(String path) { 163 Bitmap bitmap = null; 164 MediaMetadataRetriever retriever = new MediaMetadataRetriever(); 165 try { 166 retriever.setDataSource(path); 167 byte[] data = retriever.getEmbeddedPicture(); 168 if (data != null) { 169 bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); 170 } 171 if (bitmap == null) { 172 bitmap = retriever.getFrameAtTime(); 173 } 174 } catch (IllegalArgumentException e) { 175 Log.e(TAG, "MediaMetadataRetriever.setDataSource() fail:" + e.getMessage()); 176 } 177 retriever.release(); 178 return bitmap; 179 } 180} 181