15052117cc429d85cf446421ca74859f4365747d3Angus Kong/*
25052117cc429d85cf446421ca74859f4365747d3Angus Kong * Copyright (C) 2014 The Android Open Source Project
35052117cc429d85cf446421ca74859f4365747d3Angus Kong *
45052117cc429d85cf446421ca74859f4365747d3Angus Kong * Licensed under the Apache License, Version 2.0 (the "License");
55052117cc429d85cf446421ca74859f4365747d3Angus Kong * you may not use this file except in compliance with the License.
65052117cc429d85cf446421ca74859f4365747d3Angus Kong * You may obtain a copy of the License at
75052117cc429d85cf446421ca74859f4365747d3Angus Kong *
85052117cc429d85cf446421ca74859f4365747d3Angus Kong *      http://www.apache.org/licenses/LICENSE-2.0
95052117cc429d85cf446421ca74859f4365747d3Angus Kong *
105052117cc429d85cf446421ca74859f4365747d3Angus Kong * Unless required by applicable law or agreed to in writing, software
115052117cc429d85cf446421ca74859f4365747d3Angus Kong * distributed under the License is distributed on an "AS IS" BASIS,
125052117cc429d85cf446421ca74859f4365747d3Angus Kong * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135052117cc429d85cf446421ca74859f4365747d3Angus Kong * See the License for the specific language governing permissions and
145052117cc429d85cf446421ca74859f4365747d3Angus Kong * limitations under the License.
155052117cc429d85cf446421ca74859f4365747d3Angus Kong */
165052117cc429d85cf446421ca74859f4365747d3Angus Kong
175052117cc429d85cf446421ca74859f4365747d3Angus Kongpackage com.android.camera.data;
185052117cc429d85cf446421ca74859f4365747d3Angus Kong
195052117cc429d85cf446421ca74859f4365747d3Angus Kongimport android.graphics.Bitmap;
205052117cc429d85cf446421ca74859f4365747d3Angus Kongimport android.graphics.BitmapFactory;
215052117cc429d85cf446421ca74859f4365747d3Angus Kongimport android.graphics.Matrix;
225052117cc429d85cf446421ca74859f4365747d3Angus Kongimport android.graphics.Point;
235052117cc429d85cf446421ca74859f4365747d3Angus Kongimport android.media.MediaMetadataRetriever;
245052117cc429d85cf446421ca74859f4365747d3Angus Kong
252bca210e5fc8a77685775ffb403096167b017dceAngus Kongimport com.android.camera.debug.Log;
265052117cc429d85cf446421ca74859f4365747d3Angus Kong
275052117cc429d85cf446421ca74859f4365747d3Angus Kongimport java.io.InputStream;
285052117cc429d85cf446421ca74859f4365747d3Angus Kong
295052117cc429d85cf446421ca74859f4365747d3Angus Kongimport javax.microedition.khronos.opengles.GL11;
305052117cc429d85cf446421ca74859f4365747d3Angus Kong
315052117cc429d85cf446421ca74859f4365747d3Angus Kong/**
325052117cc429d85cf446421ca74859f4365747d3Angus Kong * An utility class for data in content provider.
335052117cc429d85cf446421ca74859f4365747d3Angus Kong */
348ee16b8a323ffa20e6fb1270d498ec445f64defcPaul Rohdepublic class FilmstripItemUtils {
355052117cc429d85cf446421ca74859f4365747d3Angus Kong
362bca210e5fc8a77685775ffb403096167b017dceAngus Kong    private static final Log.Tag TAG = new Log.Tag("LocalDataUtil");
375052117cc429d85cf446421ca74859f4365747d3Angus Kong
385052117cc429d85cf446421ca74859f4365747d3Angus Kong    /**
395052117cc429d85cf446421ca74859f4365747d3Angus Kong     * @param mimeType The MIME type to check.
405052117cc429d85cf446421ca74859f4365747d3Angus Kong     * @return Whether the MIME is a video type.
415052117cc429d85cf446421ca74859f4365747d3Angus Kong     */
425052117cc429d85cf446421ca74859f4365747d3Angus Kong    public static boolean isMimeTypeVideo(String mimeType) {
43e11ad6d67ad95a9ecab8a594bcb55a05708abc0fSascha Haeberling        return mimeType != null && mimeType.startsWith("video/");
445052117cc429d85cf446421ca74859f4365747d3Angus Kong    }
455052117cc429d85cf446421ca74859f4365747d3Angus Kong
465052117cc429d85cf446421ca74859f4365747d3Angus Kong    /**
47732e5c323f495346a7d938b31c180741f95a4a48Radford Juang     * Checks whether the MIME type represents an image media item.
48732e5c323f495346a7d938b31c180741f95a4a48Radford Juang     *
495052117cc429d85cf446421ca74859f4365747d3Angus Kong     * @param mimeType The MIME type to check.
505052117cc429d85cf446421ca74859f4365747d3Angus Kong     * @return Whether the MIME is a image type.
515052117cc429d85cf446421ca74859f4365747d3Angus Kong     */
525052117cc429d85cf446421ca74859f4365747d3Angus Kong    public static boolean isMimeTypeImage(String mimeType) {
53e11ad6d67ad95a9ecab8a594bcb55a05708abc0fSascha Haeberling        return mimeType != null && mimeType.startsWith("image/");
545052117cc429d85cf446421ca74859f4365747d3Angus Kong    }
555052117cc429d85cf446421ca74859f4365747d3Angus Kong
562666dc8a1c23b7c2b7c80d7c09104f113fb7dbb2Sam Judd
572666dc8a1c23b7c2b7c80d7c09104f113fb7dbb2Sam Judd    /**
582666dc8a1c23b7c2b7c80d7c09104f113fb7dbb2Sam Judd     * Decodes the dimension of a bitmap.
592666dc8a1c23b7c2b7c80d7c09104f113fb7dbb2Sam Judd     *
602666dc8a1c23b7c2b7c80d7c09104f113fb7dbb2Sam Judd     * @param is An input stream with the data of the bitmap.
612666dc8a1c23b7c2b7c80d7c09104f113fb7dbb2Sam Judd     * @return The decoded width/height is stored in Point.x/Point.y
622666dc8a1c23b7c2b7c80d7c09104f113fb7dbb2Sam Judd     *         respectively.
632666dc8a1c23b7c2b7c80d7c09104f113fb7dbb2Sam Judd     */
642666dc8a1c23b7c2b7c80d7c09104f113fb7dbb2Sam Judd    public static Point decodeBitmapDimension(InputStream is) {
652666dc8a1c23b7c2b7c80d7c09104f113fb7dbb2Sam Judd        Point size = null;
665052117cc429d85cf446421ca74859f4365747d3Angus Kong        BitmapFactory.Options justBoundsOpts = new BitmapFactory.Options();
675052117cc429d85cf446421ca74859f4365747d3Angus Kong        justBoundsOpts.inJustDecodeBounds = true;
682666dc8a1c23b7c2b7c80d7c09104f113fb7dbb2Sam Judd        BitmapFactory.decodeStream(is, null, justBoundsOpts);
695052117cc429d85cf446421ca74859f4365747d3Angus Kong        if (justBoundsOpts.outWidth > 0 && justBoundsOpts.outHeight > 0) {
702666dc8a1c23b7c2b7c80d7c09104f113fb7dbb2Sam Judd            size = new Point(justBoundsOpts.outWidth, justBoundsOpts.outHeight);
71de3e9abaa241dc2aa66e5d02ba8b7bd35e0d8f00Sam Judd        } else {
722666dc8a1c23b7c2b7c80d7c09104f113fb7dbb2Sam Judd            Log.e(TAG, "Bitmap dimension decoding failed");
735052117cc429d85cf446421ca74859f4365747d3Angus Kong        }
745052117cc429d85cf446421ca74859f4365747d3Angus Kong        return size;
755052117cc429d85cf446421ca74859f4365747d3Angus Kong    }
765052117cc429d85cf446421ca74859f4365747d3Angus Kong
775052117cc429d85cf446421ca74859f4365747d3Angus Kong    /**
785052117cc429d85cf446421ca74859f4365747d3Angus Kong     * Load the thumbnail of an image from an {@link java.io.InputStream}.
795052117cc429d85cf446421ca74859f4365747d3Angus Kong     *
805052117cc429d85cf446421ca74859f4365747d3Angus Kong     * @param stream The input stream of the image.
815052117cc429d85cf446421ca74859f4365747d3Angus Kong     * @param imageWidth Image width.
825052117cc429d85cf446421ca74859f4365747d3Angus Kong     * @param imageHeight Image height.
835052117cc429d85cf446421ca74859f4365747d3Angus Kong     * @param widthBound The bound of the width of the decoded image.
845052117cc429d85cf446421ca74859f4365747d3Angus Kong     * @param heightBound The bound of the height of the decoded image.
855052117cc429d85cf446421ca74859f4365747d3Angus Kong     * @param orientation The orientation of the image. The image will be rotated
865052117cc429d85cf446421ca74859f4365747d3Angus Kong     *                    clockwise in degrees.
875052117cc429d85cf446421ca74859f4365747d3Angus Kong     * @param maximumPixels The bound for the number of pixels of the decoded image.
885052117cc429d85cf446421ca74859f4365747d3Angus Kong     * @return {@code null} if the decoding failed.
895052117cc429d85cf446421ca74859f4365747d3Angus Kong     */
905052117cc429d85cf446421ca74859f4365747d3Angus Kong    public static Bitmap loadImageThumbnailFromStream(InputStream stream, int imageWidth,
915052117cc429d85cf446421ca74859f4365747d3Angus Kong            int imageHeight, int widthBound, int heightBound, int orientation,
925052117cc429d85cf446421ca74859f4365747d3Angus Kong            int maximumPixels) {
935052117cc429d85cf446421ca74859f4365747d3Angus Kong
945052117cc429d85cf446421ca74859f4365747d3Angus Kong        /** 32K buffer. */
955052117cc429d85cf446421ca74859f4365747d3Angus Kong        byte[] decodeBuffer = new byte[32 * 1024];
965052117cc429d85cf446421ca74859f4365747d3Angus Kong
97c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong        if (orientation % 180 != 0) {
98c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong            int dummy = imageHeight;
99c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong            imageHeight = imageWidth;
100c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong            imageWidth = dummy;
101c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong        }
102c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong
1035052117cc429d85cf446421ca74859f4365747d3Angus Kong        // Generate Bitmap of maximum size that fits into widthBound x heightBound.
1045052117cc429d85cf446421ca74859f4365747d3Angus Kong        // Algorithm: start with full size and step down in powers of 2.
1055052117cc429d85cf446421ca74859f4365747d3Angus Kong        int targetWidth = imageWidth;
1065052117cc429d85cf446421ca74859f4365747d3Angus Kong        int targetHeight = imageHeight;
1075052117cc429d85cf446421ca74859f4365747d3Angus Kong        int sampleSize = 1;
1085052117cc429d85cf446421ca74859f4365747d3Angus Kong        while (targetHeight > heightBound || targetWidth > widthBound ||
1095052117cc429d85cf446421ca74859f4365747d3Angus Kong                targetHeight > GL11.GL_MAX_TEXTURE_SIZE || targetWidth > GL11.GL_MAX_TEXTURE_SIZE ||
1105052117cc429d85cf446421ca74859f4365747d3Angus Kong                targetHeight * targetWidth > maximumPixels) {
1115052117cc429d85cf446421ca74859f4365747d3Angus Kong            sampleSize <<= 1;
1125052117cc429d85cf446421ca74859f4365747d3Angus Kong            targetWidth = imageWidth / sampleSize;
1135052117cc429d85cf446421ca74859f4365747d3Angus Kong            targetHeight = imageWidth / sampleSize;
1145052117cc429d85cf446421ca74859f4365747d3Angus Kong        }
1155052117cc429d85cf446421ca74859f4365747d3Angus Kong
1165052117cc429d85cf446421ca74859f4365747d3Angus Kong        // For large (> MAXIMUM_TEXTURE_SIZE) high aspect ratio (panorama)
1175052117cc429d85cf446421ca74859f4365747d3Angus Kong        // Bitmap requests:
1185052117cc429d85cf446421ca74859f4365747d3Angus Kong        //   Step 1: ask for double size.
1195052117cc429d85cf446421ca74859f4365747d3Angus Kong        //   Step 2: scale maximum edge down to MAXIMUM_TEXTURE_SIZE.
1205052117cc429d85cf446421ca74859f4365747d3Angus Kong        //
1215052117cc429d85cf446421ca74859f4365747d3Angus Kong        // Here's the step 1: double size.
1225052117cc429d85cf446421ca74859f4365747d3Angus Kong        if ((heightBound > GL11.GL_MAX_TEXTURE_SIZE || widthBound > GL11.GL_MAX_TEXTURE_SIZE) &&
1235052117cc429d85cf446421ca74859f4365747d3Angus Kong                targetWidth * targetHeight < maximumPixels / 4 && sampleSize > 1) {
1245052117cc429d85cf446421ca74859f4365747d3Angus Kong            sampleSize >>= 2;
1255052117cc429d85cf446421ca74859f4365747d3Angus Kong        }
1265052117cc429d85cf446421ca74859f4365747d3Angus Kong
1275052117cc429d85cf446421ca74859f4365747d3Angus Kong        BitmapFactory.Options opts = new BitmapFactory.Options();
1285052117cc429d85cf446421ca74859f4365747d3Angus Kong        opts.inSampleSize = sampleSize;
1295052117cc429d85cf446421ca74859f4365747d3Angus Kong        opts.inTempStorage = decodeBuffer;
1305052117cc429d85cf446421ca74859f4365747d3Angus Kong        Bitmap b = BitmapFactory.decodeStream(stream, null, opts);
1315052117cc429d85cf446421ca74859f4365747d3Angus Kong
1325052117cc429d85cf446421ca74859f4365747d3Angus Kong        if (b == null) {
1335052117cc429d85cf446421ca74859f4365747d3Angus Kong            return null;
1345052117cc429d85cf446421ca74859f4365747d3Angus Kong        }
1355052117cc429d85cf446421ca74859f4365747d3Angus Kong
1365052117cc429d85cf446421ca74859f4365747d3Angus Kong        // Step 2: scale maximum edge down to maximum texture size.
1375052117cc429d85cf446421ca74859f4365747d3Angus Kong        // If Bitmap maximum edge > MAXIMUM_TEXTURE_SIZE, which can happen for panoramas,
1385052117cc429d85cf446421ca74859f4365747d3Angus Kong        // scale to fit in MAXIMUM_TEXTURE_SIZE.
1395052117cc429d85cf446421ca74859f4365747d3Angus Kong        if (b.getWidth() > GL11.GL_MAX_TEXTURE_SIZE || b.getHeight() >
1405052117cc429d85cf446421ca74859f4365747d3Angus Kong                GL11.GL_MAX_TEXTURE_SIZE) {
1415052117cc429d85cf446421ca74859f4365747d3Angus Kong            int maxEdge = Math.max(b.getWidth(), b.getHeight());
1425052117cc429d85cf446421ca74859f4365747d3Angus Kong            b = Bitmap.createScaledBitmap(b, b.getWidth() * GL11.GL_MAX_TEXTURE_SIZE / maxEdge,
1435052117cc429d85cf446421ca74859f4365747d3Angus Kong                    b.getHeight() * GL11.GL_MAX_TEXTURE_SIZE / maxEdge, false);
1445052117cc429d85cf446421ca74859f4365747d3Angus Kong        }
1455052117cc429d85cf446421ca74859f4365747d3Angus Kong
1465052117cc429d85cf446421ca74859f4365747d3Angus Kong        // Not called often because most modes save image data non-rotated.
1475052117cc429d85cf446421ca74859f4365747d3Angus Kong        if (orientation != 0 && b != null) {
1485052117cc429d85cf446421ca74859f4365747d3Angus Kong            Matrix m = new Matrix();
1495052117cc429d85cf446421ca74859f4365747d3Angus Kong            m.setRotate(orientation);
1505052117cc429d85cf446421ca74859f4365747d3Angus Kong            b = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), m, false);
1515052117cc429d85cf446421ca74859f4365747d3Angus Kong        }
1525052117cc429d85cf446421ca74859f4365747d3Angus Kong
1535052117cc429d85cf446421ca74859f4365747d3Angus Kong        return b;
1545052117cc429d85cf446421ca74859f4365747d3Angus Kong    }
1555052117cc429d85cf446421ca74859f4365747d3Angus Kong
1565052117cc429d85cf446421ca74859f4365747d3Angus Kong    /**
1575052117cc429d85cf446421ca74859f4365747d3Angus Kong     * Loads the thumbnail of a video.
1585052117cc429d85cf446421ca74859f4365747d3Angus Kong     *
1595052117cc429d85cf446421ca74859f4365747d3Angus Kong     * @param path The path to the video file.
1605052117cc429d85cf446421ca74859f4365747d3Angus Kong     * @return {@code null} if the loading failed.
1615052117cc429d85cf446421ca74859f4365747d3Angus Kong     */
1625052117cc429d85cf446421ca74859f4365747d3Angus Kong    public static Bitmap loadVideoThumbnail(String path) {
1635052117cc429d85cf446421ca74859f4365747d3Angus Kong        Bitmap bitmap = null;
1645052117cc429d85cf446421ca74859f4365747d3Angus Kong        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
1655052117cc429d85cf446421ca74859f4365747d3Angus Kong        try {
1665052117cc429d85cf446421ca74859f4365747d3Angus Kong            retriever.setDataSource(path);
1675052117cc429d85cf446421ca74859f4365747d3Angus Kong            byte[] data = retriever.getEmbeddedPicture();
1685052117cc429d85cf446421ca74859f4365747d3Angus Kong            if (data != null) {
1695052117cc429d85cf446421ca74859f4365747d3Angus Kong                bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
1705052117cc429d85cf446421ca74859f4365747d3Angus Kong            }
1715052117cc429d85cf446421ca74859f4365747d3Angus Kong            if (bitmap == null) {
1725052117cc429d85cf446421ca74859f4365747d3Angus Kong                bitmap = retriever.getFrameAtTime();
1735052117cc429d85cf446421ca74859f4365747d3Angus Kong            }
1745052117cc429d85cf446421ca74859f4365747d3Angus Kong        } catch (IllegalArgumentException e) {
1755052117cc429d85cf446421ca74859f4365747d3Angus Kong            Log.e(TAG, "MediaMetadataRetriever.setDataSource() fail:" + e.getMessage());
1765052117cc429d85cf446421ca74859f4365747d3Angus Kong        }
1775052117cc429d85cf446421ca74859f4365747d3Angus Kong        retriever.release();
1785052117cc429d85cf446421ca74859f4365747d3Angus Kong        return bitmap;
1795052117cc429d85cf446421ca74859f4365747d3Angus Kong    }
1805052117cc429d85cf446421ca74859f4365747d3Angus Kong}
181