Home | History | Annotate | Download | only in media
      1 /*
      2  * Copyright (C) 2009 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.cooliris.media;
     18 
     19 import java.io.DataInputStream;
     20 import java.io.DataOutputStream;
     21 import java.io.File;
     22 import java.io.FileInputStream;
     23 import java.io.FileOutputStream;
     24 import java.io.IOException;
     25 import java.io.InputStream;
     26 import java.io.OutputStream;
     27 import java.util.List;
     28 
     29 import android.content.ActivityNotFoundException;
     30 import android.content.ContentResolver;
     31 import android.content.ContentUris;
     32 import android.content.Context;
     33 import android.content.Intent;
     34 import android.database.Cursor;
     35 import android.graphics.Bitmap;
     36 import android.graphics.BitmapFactory;
     37 import android.net.Uri;
     38 import android.provider.MediaStore;
     39 import android.widget.Toast;
     40 
     41 import com.cooliris.app.App;
     42 import com.cooliris.app.Res;
     43 
     44 public class Utils {
     45     private static final int UNCONSTRAINED = -1;
     46 
     47     public static void playVideo(final Context context, final MediaItem item) {
     48         // this is a video
     49         App.get(context).getHandler().post(new Runnable() {
     50             public void run() {
     51                 try {
     52                     Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(item.mContentUri));
     53                     intent.setDataAndType(Uri.parse(item.mContentUri), item.mMimeType);
     54                     context.startActivity(intent);
     55                 } catch (ActivityNotFoundException e) {
     56                     Toast.makeText(context, context.getResources().getString(Res.string.video_err), Toast.LENGTH_SHORT).show();
     57                 }
     58             }
     59         });
     60     }
     61 
     62     public static final void writeUTF(DataOutputStream dos, String string) throws IOException {
     63         if (string == null) {
     64             dos.writeUTF(new String());
     65         } else {
     66             dos.writeUTF(string);
     67         }
     68     }
     69 
     70     public static final String readUTF(DataInputStream dis) throws IOException {
     71         String retVal = dis.readUTF();
     72         if (retVal.length() == 0)
     73             return null;
     74         return retVal;
     75     }
     76 
     77     public static final Bitmap resizeBitmap(Bitmap bitmap, int maxSize) {
     78         int srcWidth = bitmap.getWidth();
     79         int srcHeight = bitmap.getHeight();
     80         int width = maxSize;
     81         int height = maxSize;
     82         boolean needsResize = false;
     83         if (srcWidth > srcHeight) {
     84             if (srcWidth > maxSize) {
     85                 needsResize = true;
     86                 height = ((maxSize * srcHeight) / srcWidth);
     87             }
     88         } else {
     89             if (srcHeight > maxSize) {
     90                 needsResize = true;
     91                 width = ((maxSize * srcWidth) / srcHeight);
     92             }
     93         }
     94         if (needsResize) {
     95             Bitmap retVal = Bitmap.createScaledBitmap(bitmap, width, height, true);
     96             return retVal;
     97         } else {
     98             return bitmap;
     99         }
    100     }
    101 
    102     private static final long POLY64REV = 0x95AC9329AC4BC9B5L;
    103     private static final long INITIALCRC = 0xFFFFFFFFFFFFFFFFL;
    104 
    105     private static boolean init = false;
    106     private static long[] CRCTable = new long[256];
    107 
    108     /**
    109      * A function thats returns a 64-bit crc for string
    110      *
    111      * @param in
    112      *            : input string
    113      * @return 64-bit crc value
    114      */
    115     public static final long Crc64Long(String in) {
    116         if (in == null || in.length() == 0) {
    117             return 0;
    118         }
    119         // http://bioinf.cs.ucl.ac.uk/downloads/crc64/crc64.c
    120         long crc = INITIALCRC, part;
    121         if (!init) {
    122             for (int i = 0; i < 256; i++) {
    123                 part = i;
    124                 for (int j = 0; j < 8; j++) {
    125                     int value = ((int) part & 1);
    126                     if (value != 0)
    127                         part = (part >> 1) ^ POLY64REV;
    128                     else
    129                         part >>= 1;
    130                 }
    131                 CRCTable[i] = part;
    132             }
    133             init = true;
    134         }
    135         int length = in.length();
    136         for (int k = 0; k < length; ++k) {
    137             char c = in.charAt(k);
    138             crc = CRCTable[(((int) crc) ^ c) & 0xff] ^ (crc >> 8);
    139         }
    140         return crc;
    141     }
    142 
    143     /**
    144      * A function that returns a human readable hex string of a Crx64
    145      *
    146      * @param in
    147      *            : input string
    148      * @return hex string of the 64-bit CRC value
    149      */
    150     public static final String Crc64(String in) {
    151         if (in == null)
    152             return null;
    153         long crc = Crc64Long(in);
    154         /*
    155          * The output is done in two parts to avoid problems with
    156          * architecture-dependent word order
    157          */
    158         int low = ((int) crc) & 0xffffffff;
    159         int high = ((int) (crc >> 32)) & 0xffffffff;
    160         String outVal = Integer.toHexString(high) + Integer.toHexString(low);
    161         return outVal;
    162     }
    163 
    164     public static long getBucketIdFromUri(final ContentResolver cr, final Uri uri) {
    165         if (uri.getScheme().equals("file")) {
    166             String string = "/";
    167             List<String> paths = uri.getPathSegments();
    168             int numPaths = paths.size();
    169             for (int i = 0; i < numPaths - 1; ++i) {
    170                 string += paths.get(i);
    171                 if (i != numPaths - 2)
    172                     string += "/";
    173             }
    174             return LocalDataSource.getBucketId(string);
    175         } else {
    176             Cursor cursor = null;
    177             try {
    178                 long id = ContentUris.parseId(uri);
    179                 cursor = cr.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
    180                         new String[] { MediaStore.Images.ImageColumns.BUCKET_ID }, MediaStore.Images.ImageColumns._ID + "=" + id,
    181                         null, null);
    182                 if (cursor != null) {
    183                     if (cursor.moveToFirst()) {
    184                         long setVal = cursor.getLong(0);
    185                         cursor.close();
    186                         return setVal;
    187                     }
    188                 }
    189                 cursor = cr.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
    190                         new String[] { MediaStore.Video.VideoColumns.BUCKET_ID }, MediaStore.Images.ImageColumns._ID + "=" + id,
    191                         null, null);
    192                 if (cursor != null) {
    193                     if (cursor.moveToFirst()) {
    194                         long setVal = cursor.getLong(0);
    195                         cursor.close();
    196                         return setVal;
    197                     }
    198                 }
    199             } catch (Exception e) {
    200                 ;
    201             }
    202             return Shared.INVALID;
    203         }
    204     }
    205 
    206     public static String getBucketNameFromUri(final ContentResolver cr, final Uri uri) {
    207         final long bucketId = getBucketIdFromUri(cr, uri);
    208         if (bucketId != Shared.INVALID) {
    209             try {
    210                 Cursor cursor = cr.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
    211                         new String[] { MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME },
    212                         MediaStore.Images.ImageColumns.BUCKET_ID + "='" + bucketId + "'", null, null);
    213                 if (cursor != null) {
    214                     if (cursor.moveToFirst()) {
    215                         String setName = cursor.getString(0);
    216                         cursor.close();
    217                         return setName;
    218                     }
    219                 }
    220                 cursor = cr.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
    221                         new String[] { MediaStore.Video.VideoColumns.BUCKET_DISPLAY_NAME }, MediaStore.Video.VideoColumns.BUCKET_ID
    222                                 + "='" + bucketId + "'", null, null);
    223                 if (cursor != null) {
    224                     if (cursor.moveToFirst()) {
    225                         String setName = cursor.getString(0);
    226                         cursor.close();
    227                         return setName;
    228                     }
    229                 }
    230             } catch (Exception e) {
    231                 ;
    232             }
    233         }
    234         return "";
    235     }
    236 
    237     // Copies src file to dst file.
    238     // If the dst file does not exist, it is created
    239     public static void Copy(File src, File dst) throws IOException {
    240         InputStream in = new FileInputStream(src);
    241         OutputStream out = new FileOutputStream(dst);
    242         copyStream(in, out);
    243     }
    244 
    245     public static void copyStream(InputStream in, OutputStream out) throws IOException {
    246         // Transfer bytes from in to out
    247         byte[] buf = new byte[1024];
    248         int len;
    249         while ((len = in.read(buf)) > 0) {
    250             out.write(buf, 0, len);
    251         }
    252         in.close();
    253         out.close();
    254     }
    255 
    256     /*
    257      * Compute the sample size as a function of minSideLength
    258      * and maxNumOfPixels.
    259      * minSideLength is used to specify that minimal width or height of a
    260      * bitmap.
    261      * maxNumOfPixels is used to specify the maximal size in pixels that is
    262      * tolerable in terms of memory usage.
    263      *
    264      * The function returns a sample size based on the constraints.
    265      * Both size and minSideLength can be passed in as IImage.UNCONSTRAINED,
    266      * which indicates no care of the corresponding constraint.
    267      * The functions prefers returning a sample size that
    268      * generates a smaller bitmap, unless minSideLength = IImage.UNCONSTRAINED.
    269      *
    270      * Also, the function rounds up the sample size to a power of 2 or multiple
    271      * of 8 because BitmapFactory only honors sample size this way.
    272      * For example, BitmapFactory downsamples an image by 2 even though the
    273      * request is 3. So we round up the sample size to avoid OOM.
    274      */
    275     public static int computeSampleSize(BitmapFactory.Options options,
    276             int minSideLength, int maxNumOfPixels) {
    277         int initialSize = computeInitialSampleSize(options, minSideLength,
    278                 maxNumOfPixels);
    279 
    280         int roundedSize;
    281         if (initialSize <= 8 ) {
    282             roundedSize = 1;
    283             while (roundedSize < initialSize) {
    284                 roundedSize <<= 1;
    285             }
    286         } else {
    287             roundedSize = (initialSize + 7) / 8 * 8;
    288         }
    289 
    290         return roundedSize;
    291     }
    292 
    293     public static int computeInitialSampleSize(BitmapFactory.Options options,
    294             int minSideLength, int maxNumOfPixels) {
    295         double w = options.outWidth;
    296         double h = options.outHeight;
    297 
    298         int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? 1 :
    299                 (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
    300         int upperBound = (minSideLength == UNCONSTRAINED) ? 128 :
    301                 (int) Math.min(Math.floor(w / minSideLength),
    302                 Math.floor(h / minSideLength));
    303 
    304         if (upperBound < lowerBound) {
    305             // return the larger one when there is no overlapping zone.
    306             return lowerBound;
    307         }
    308 
    309         if ((maxNumOfPixels == UNCONSTRAINED) &&
    310                 (minSideLength == UNCONSTRAINED)) {
    311             return 1;
    312         } else if (minSideLength == UNCONSTRAINED) {
    313             return lowerBound;
    314         } else {
    315             return upperBound;
    316         }
    317     }
    318 
    319 }
    320