/***************************************************************************** * Thumbnailer.java ***************************************************************************** * Copyright © 2011-2012 VLC authors and VideoLAN * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ package org.videolan.vlc; import java.lang.Thread.State; import java.lang.ref.WeakReference; import java.nio.ByteBuffer; import java.util.LinkedList; import java.util.Queue; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.videolan.libvlc.LibVLC; import org.videolan.libvlc.util.VLCUtil; import org.videolan.vlc.interfaces.IVideoBrowser; import org.videolan.vlc.util.BitmapUtil; import org.videolan.vlc.util.VLCInstance; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.util.DisplayMetrics; import android.util.Log; import android.view.Display; public class Thumbnailer implements Runnable { public final static String TAG = "VLC/Thumbnailer"; private WeakReference<IVideoBrowser> mVideoBrowser; private final Queue<MediaWrapper> mItems = new LinkedList<MediaWrapper>(); private boolean isStopping = false; private final Lock lock = new ReentrantLock(); private final Condition notEmpty = lock.newCondition(); protected Thread mThread; private LibVLC mLibVlc; private int totalCount; private final String mPrefix; public Thumbnailer(Context context, Display display) { DisplayMetrics metrics = new DisplayMetrics(); display.getMetrics(metrics); mPrefix = context.getResources().getString(R.string.thumbnail); } public void start(IVideoBrowser videoBrowser) { mLibVlc = VLCInstance.get(); isStopping = false; if (mThread == null || mThread.getState() == State.TERMINATED) { mVideoBrowser = new WeakReference<IVideoBrowser>(videoBrowser); mThread = new Thread(this); mThread.start(); } } public void stop() { isStopping = true; if (mThread != null) mThread.interrupt(); } /** * Remove all the thumbnail jobs. */ public void clearJobs() { lock.lock(); try { mItems.clear(); totalCount = 0; } finally { lock.unlock(); } } /** * Gives the count of pending thumbnails * @return totalCount */ public int getJobsCount(){ int count; lock.lock(); count = totalCount; lock.unlock(); return count; } /** * Add a new media item to create its thumbnail. * @param item media wrapper of the file browser item. */ public void addJob(MediaWrapper item) { if(BitmapUtil.getPictureFromCache(item) != null || item.isPictureParsed()) return; lock.lock(); try { mItems.add(item); totalCount++; notEmpty.signal(); } finally { lock.unlock(); } Log.i(TAG, "Job added!"); } /** * Thread main function. */ @Override public void run() { int count = 0; int total = 0; Log.d(TAG, "Thumbnailer started"); while (!isStopping) { if (mVideoBrowser != null && mVideoBrowser.get() != null) mVideoBrowser.get().resetBarrier(); lock.lock(); // Get the id of the file browser item to create its thumbnail. boolean interrupted = false; while (mItems.size() == 0) { try { if (mVideoBrowser != null && mVideoBrowser.get() != null) { mVideoBrowser.get().hideProgressBar(); mVideoBrowser.get().clearTextInfo(); } totalCount = 0; notEmpty.await(); } catch (InterruptedException e) { interrupted = true; Log.i(TAG, "interruption probably requested by stop()"); break; } } if (interrupted) { lock.unlock(); break; } total = totalCount; MediaWrapper item = mItems.poll(); lock.unlock(); if (mVideoBrowser != null && mVideoBrowser.get() != null) { mVideoBrowser.get().showProgressBar(); mVideoBrowser.get().sendTextInfo(String.format("%s %s", mPrefix, item.getFileName()), count, total); } count++; if (item.getArtworkURL() != null) continue; //no need for thumbnail, we have a cover int width = (VLCApplication.getAppResources().getDimensionPixelSize(R.dimen.grid_card_thumb_width)); int height = (VLCApplication.getAppResources().getDimensionPixelSize(R.dimen.grid_card_thumb_height)); //Get bitmap byte[] b = VLCUtil.getThumbnail(VLCInstance.get(), item.getUri(), width, height); if (b == null) {// We were not able to create a thumbnail for this item, store a dummy MediaDatabase.setPicture(item, Bitmap.createBitmap(1, 1, Config.ARGB_8888)); continue; } // Create the bitmap Bitmap thumbnail = Bitmap.createBitmap(width, height, Config.ARGB_8888); thumbnail.copyPixelsFromBuffer(ByteBuffer.wrap(b)); Log.i(TAG, "Thumbnail created for " + item.getFileName()); MediaDatabase.setPicture(item, thumbnail); // Post to the file browser the new item. if (mVideoBrowser != null && mVideoBrowser.get() != null) { mVideoBrowser.get().setItemToUpdate(item); // Wait for the file browser to process the change. try { mVideoBrowser.get().await(); } catch (InterruptedException e) { Log.i(TAG, "interruption probably requested by stop()"); break; } catch (BrokenBarrierException e) { Log.e(TAG, "Unexpected BrokenBarrierException"); e.printStackTrace(); break; } } } /* cleanup */ if (mVideoBrowser != null && mVideoBrowser.get() != null) { mVideoBrowser.get().hideProgressBar(); mVideoBrowser.get().clearTextInfo(); mVideoBrowser.clear(); } Log.d(TAG, "Thumbnailer stopped"); } public void setVideoBrowser(IVideoBrowser browser){ mVideoBrowser = new WeakReference<IVideoBrowser>(browser); } }