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.ByteArrayInputStream;
     20 import java.io.DataInputStream;
     21 import java.io.IOException;
     22 import java.net.URISyntaxException;
     23 
     24 import android.content.Context;
     25 import android.graphics.Bitmap;
     26 import android.graphics.BitmapFactory;
     27 import android.net.Uri;
     28 import android.provider.MediaStore;
     29 import android.util.Log;
     30 import android.os.Process;
     31 
     32 import com.cooliris.cache.CacheService;
     33 
     34 public final class MediaItemTexture extends Texture {
     35     public static final int MAX_FACES = 1;
     36     private static final String TAG = "MediaItemTexture";
     37     private static final int CACHE_HEADER_SIZE = 12;
     38 
     39     private final Config mConfig;
     40     private final MediaItem mItem;
     41     private Context mContext;
     42     private boolean mIsRetrying;
     43     private boolean mCached;
     44 
     45     public static final class Config {
     46         public int thumbnailWidth;
     47         public int thumbnailHeight;
     48     }
     49 
     50     public MediaItemTexture(Context context, Config config, MediaItem item) {
     51         mConfig = config;
     52         mContext = context;
     53         mItem = item;
     54         mCached = computeCache();
     55     }
     56 
     57     private boolean computeCache() {
     58         final Config config = mConfig;
     59         final MediaItem item = mItem;
     60         DiskCache cache = null;
     61         MediaSet parentMediaSet = item.mParentMediaSet;
     62         if (config != null && parentMediaSet != null && parentMediaSet.mDataSource != null) {
     63             cache = parentMediaSet.mDataSource.getThumbnailCache();
     64             if (cache == LocalDataSource.sThumbnailCache) {
     65                 if (item.mMimeType != null && item.mMimeType.contains("video")) {
     66                     cache = LocalDataSource.sThumbnailCacheVideo;
     67                 }
     68             }
     69         }
     70         if (cache == null) {
     71             return false;
     72         }
     73         synchronized (cache) {
     74             long id = parentMediaSet.mPicasaAlbumId == Shared.INVALID ? Utils.Crc64Long(item.mFilePath) : item.mId;
     75             return cache.isDataAvailable(id, item.mDateModifiedInSec * 1000);
     76         }
     77     }
     78 
     79     @Override
     80     public boolean isUncachedVideo() {
     81         if (isCached())
     82             return false;
     83         if (mItem.mParentMediaSet == null || mItem.mMimeType == null)
     84             return false;
     85         if (mItem.mParentMediaSet.mPicasaAlbumId == Shared.INVALID && mItem.mMimeType.contains("video")) {
     86             return true;
     87         } else {
     88             return false;
     89         }
     90     }
     91 
     92     @Override
     93     public boolean isCached() {
     94         return mCached;
     95     }
     96 
     97     protected Bitmap load(RenderView view) {
     98         final Config config = mConfig;
     99         final MediaItem item = mItem;
    100 
    101         // Special case for non-MediaStore content URIs, do not cache the
    102         // thumbnail.
    103         String uriString = item.mContentUri;
    104         if (uriString != null) {
    105             Uri uri = Uri.parse(uriString);
    106             if (uri.getScheme().equals("content") && !uri.getAuthority().equals("media")) {
    107                 try {
    108                     return UriTexture.createFromUri(mContext, item.mThumbnailUri, 128, 128, 0, null);
    109                 } catch (IOException e) {
    110                     return null;
    111                 } catch (URISyntaxException e) {
    112                     return null;
    113                 }
    114             }
    115         }
    116 
    117         // Look up the thumbnail in the disk cache.
    118         if (config == null) {
    119             Bitmap retVal = null;
    120             try {
    121                 if (mItem.getMediaType() == MediaItem.MEDIA_TYPE_IMAGE) {
    122                     Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
    123                     try {
    124                         // We first dirty the cache if the timestamp has changed
    125                         DiskCache cache = null;
    126                         MediaSet parentMediaSet = item.mParentMediaSet;
    127                         if (parentMediaSet != null && parentMediaSet.mDataSource != null) {
    128                             cache = parentMediaSet.mDataSource.getThumbnailCache();
    129                             if (cache == LocalDataSource.sThumbnailCache) {
    130                                 if (item.mMimeType != null && item.mMimeType.contains("video")) {
    131                                     cache = LocalDataSource.sThumbnailCacheVideo;
    132                                 }
    133                                 final long crc64 = Utils.Crc64Long(item.mFilePath);
    134                                 if (!cache.isDataAvailable(crc64, item.mDateModifiedInSec * 1000)) {
    135                                     UriTexture.invalidateCache(crc64, UriTexture.MAX_RESOLUTION);
    136                                 }
    137                             }
    138                         }
    139                         retVal = UriTexture.createFromUri(mContext, mItem.mContentUri, UriTexture.MAX_RESOLUTION,
    140                                 UriTexture.MAX_RESOLUTION, Utils.Crc64Long(item.mFilePath), null);
    141                     } catch (IOException e) {
    142                         ;
    143                     } catch (URISyntaxException e) {
    144                         ;
    145                     }
    146                     Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    147                 } else {
    148                     Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
    149                     new Thread() {
    150                         public void run() {
    151                             try {
    152                                 Thread.sleep(5000);
    153                             } catch (InterruptedException e) {
    154                                 ;
    155                             }
    156                             try {
    157                                 MediaStore.Video.Thumbnails.cancelThumbnailRequest(mContext.getContentResolver(), mItem.mId);
    158                             } catch (Exception e) {
    159                                 ;
    160                             }
    161                         }
    162                     }.start();
    163                     retVal = MediaStore.Video.Thumbnails.getThumbnail(mContext.getContentResolver(), mItem.mId,
    164                             MediaStore.Video.Thumbnails.MINI_KIND, null);
    165                     Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    166                 }
    167             } catch (OutOfMemoryError e) {
    168                 Log.i(TAG, "Bitmap creation fail, outofmemory");
    169                 view.handleLowMemory();
    170                 try {
    171                     if (!mIsRetrying) {
    172                         Thread.sleep(1000);
    173                         mIsRetrying = true;
    174                         retVal = load(view);
    175                     }
    176                 } catch (InterruptedException eInterrupted) {
    177 
    178                 }
    179             }
    180             return retVal;
    181         } else {
    182             byte[] data = null;
    183             MediaSet parentMediaSet = item.mParentMediaSet;
    184             if (parentMediaSet != null && !parentMediaSet.mIsLocal) {
    185                 DiskCache thumbnailCache = parentMediaSet.mDataSource.getThumbnailCache();
    186                 data = thumbnailCache.get(item.mId, 0);
    187                 if (data == null) {
    188                     // We need to generate the cache.
    189                     try {
    190                         Bitmap retVal = UriTexture.createFromUri(mContext, item.mThumbnailUri, 256, 256, 0, null);
    191                         data = CacheService.writeBitmapToCache(thumbnailCache, item.mId, item.mId, retVal, config.thumbnailWidth,
    192                                 config.thumbnailHeight, item.mDateModifiedInSec * 1000);
    193                     } catch (IOException e) {
    194                         return null;
    195                     } catch (URISyntaxException e) {
    196                         return null;
    197                     }
    198                 }
    199             } else {
    200                 long dateToUse = (item.mDateAddedInSec > item.mDateModifiedInSec) ? item.mDateAddedInSec : item.mDateModifiedInSec;
    201                 data = CacheService.queryThumbnail(mContext, Utils.Crc64Long(item.mFilePath), item.mId,
    202                         item.getMediaType() == MediaItem.MEDIA_TYPE_VIDEO, dateToUse * 1000);
    203             }
    204             if (data != null) {
    205                 try {
    206                     // Parse record header.
    207                     final ByteArrayInputStream cacheInput = new ByteArrayInputStream(data);
    208                     final DataInputStream dataInput = new DataInputStream(cacheInput);
    209                     item.mThumbnailId = dataInput.readLong();
    210                     item.mThumbnailFocusX = dataInput.readShort();
    211                     item.mThumbnailFocusY = dataInput.readShort();
    212                     // Decode the thumbnail.
    213                     final BitmapFactory.Options options = new BitmapFactory.Options();
    214                     options.inDither = true;
    215                     options.inScaled = false;
    216                     options.inPreferredConfig = Bitmap.Config.RGB_565;
    217                     final Bitmap bitmap = BitmapFactory.decodeByteArray(data, CACHE_HEADER_SIZE, data.length - CACHE_HEADER_SIZE,
    218                             options);
    219                     return bitmap;
    220                 } catch (IOException e) {
    221                     // Fall through to regenerate the cached thumbnail.
    222                 }
    223             }
    224         }
    225         return null;
    226     }
    227 }
    228