/*
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.imagepipeline.producers;
import java.util.Map;
import java.util.concurrent.Executor;
import android.graphics.Bitmap;
import android.media.ThumbnailUtils;
import android.provider.MediaStore;
import com.facebook.common.internal.ImmutableMap;
import com.facebook.common.internal.VisibleForTesting;
import com.facebook.common.references.CloseableReference;
import com.facebook.common.references.ResourceReleaser;
import com.facebook.imagepipeline.image.CloseableImage;
import com.facebook.imagepipeline.image.CloseableStaticBitmap;
import com.facebook.imagepipeline.image.ImmutableQualityInfo;
import com.facebook.imagepipeline.request.ImageRequest;
/**
* A producer that creates video thumbnails.
*
* <p>At present, these thumbnails are created on the java heap rather than being pinned
* purgeables. This is deemed okay as the thumbnails are only very small.
*/
public class LocalVideoThumbnailProducer implements
Producer<CloseableReference<CloseableImage>> {
@VisibleForTesting static final String PRODUCER_NAME = "VideoThumbnailProducer";
@VisibleForTesting static final String CREATED_THUMBNAIL = "createdThumbnail";
private final Executor mExecutor;
public LocalVideoThumbnailProducer(Executor executor) {
mExecutor = executor;
}
@Override
public void produceResults(
final Consumer<CloseableReference<CloseableImage>> consumer,
final ProducerContext producerContext) {
final ProducerListener listener = producerContext.getListener();
final String requestId = producerContext.getId();
final ImageRequest imageRequest = producerContext.getImageRequest();
final StatefulProducerRunnable cancellableProducerRunnable =
new StatefulProducerRunnable<CloseableReference<CloseableImage>>(
consumer,
listener,
PRODUCER_NAME,
requestId) {
@Override
protected CloseableReference<CloseableImage> getResult() throws Exception {
Bitmap thumbnailBitmap = ThumbnailUtils.createVideoThumbnail(
imageRequest.getSourceFile().getPath(),
calculateKind(imageRequest));
if (thumbnailBitmap == null) {
return null;
}
return CloseableReference.<CloseableImage>of(
new CloseableStaticBitmap(
thumbnailBitmap,
new ResourceReleaser<Bitmap>() {
@Override
public void release(Bitmap value) {
value.recycle();
}
},
ImmutableQualityInfo.FULL_QUALITY));
}
@Override
protected Map<String, String> getExtraMapOnSuccess(
final CloseableReference<CloseableImage> result) {
return ImmutableMap.of(CREATED_THUMBNAIL, String.valueOf(result != null));
}
@Override
protected void disposeResult(CloseableReference<CloseableImage> result) {
CloseableReference.closeSafely(result);
}
};
producerContext.addCallbacks(
new BaseProducerContextCallbacks() {
@Override
public void onCancellationRequested() {
cancellableProducerRunnable.cancel();
}
});
mExecutor.execute(cancellableProducerRunnable);
}
private static int calculateKind(ImageRequest imageRequest) {
if (imageRequest.getPreferredWidth() > 96 || imageRequest.getPreferredHeight() > 96) {
return MediaStore.Images.Thumbnails.MINI_KIND;
}
return MediaStore.Images.Thumbnails.MICRO_KIND;
}
}