Commit 25a3837e authored by Xing Liu's avatar Xing Liu Committed by Commit Bot

Android Video Thumbnail: Hook video thumbnail backend to UI.

This CL hooks the video thumbnail backend to the UI layer of new
download home.

Bug: 826021
Change-Id: I190ad09e8231d94d7546128bd1d22dc39f4d5f35
Reviewed-on: https://chromium-review.googlesource.com/1247529
Commit-Queue: Xing Liu <xingliu@chromium.org>
Reviewed-by: default avatarDavid Trainor <dtrainor@chromium.org>
Cr-Commit-Position: refs/heads/master@{#595706}
parent 39b15590
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
android:id="@+id/thumbnail" android:id="@+id/thumbnail"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="200dp" android:layout_height="200dp"
android:scaleType="centerInside" android:scaleType="centerCrop"
android:adjustViewBounds="true" android:adjustViewBounds="true"
app:layout_column="0" app:layout_column="0"
app:layout_row="0" app:layout_row="0"
......
...@@ -19,9 +19,9 @@ public class DownloadMediaParserBridge { ...@@ -19,9 +19,9 @@ public class DownloadMediaParserBridge {
* @param totalSize Total size of the media file. * @param totalSize Total size of the media file.
* @param callback Callback to get the result. * @param callback Callback to get the result.
*/ */
public DownloadMediaParserBridge(String mimeType, String filePath, long totalSize, public DownloadMediaParserBridge(
Callback<DownloadMediaData> callback) { String mimeType, String filePath, Callback<DownloadMediaData> callback) {
mNativeDownloadMediaParserBridge = nativeInit(mimeType, filePath, totalSize, callback); mNativeDownloadMediaParserBridge = nativeInit(mimeType, filePath, callback);
} }
/** /**
...@@ -43,7 +43,7 @@ public class DownloadMediaParserBridge { ...@@ -43,7 +43,7 @@ public class DownloadMediaParserBridge {
} }
private native long nativeInit( private native long nativeInit(
String mimeType, String filePath, long totalSize, Callback<DownloadMediaData> callback); String mimeType, String filePath, Callback<DownloadMediaData> callback);
private native void nativeDestory(long nativeDownloadMediaParserBridge); private native void nativeDestory(long nativeDownloadMediaParserBridge);
private native void nativeStart(long nativeDownloadMediaParserBridge); private native void nativeStart(long nativeDownloadMediaParserBridge);
} }
...@@ -7,14 +7,17 @@ package org.chromium.chrome.browser.download.home.glue; ...@@ -7,14 +7,17 @@ package org.chromium.chrome.browser.download.home.glue;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import org.chromium.base.Callback; import org.chromium.base.Callback;
import org.chromium.chrome.browser.widget.ThumbnailProvider;
import org.chromium.chrome.browser.widget.ThumbnailProvider.ThumbnailRequest; import org.chromium.chrome.browser.widget.ThumbnailProvider.ThumbnailRequest;
import org.chromium.chrome.browser.widget.ThumbnailProviderImpl;
import org.chromium.components.offline_items_collection.OfflineContentProvider;
import org.chromium.components.offline_items_collection.OfflineItem; import org.chromium.components.offline_items_collection.OfflineItem;
import org.chromium.components.offline_items_collection.OfflineItemVisuals; import org.chromium.components.offline_items_collection.OfflineItemVisuals;
import org.chromium.components.offline_items_collection.VisualsCallback; import org.chromium.components.offline_items_collection.VisualsCallback;
/** /**
* Glue class responsible for connecting the current downloads and {@link OfflineContentProvider} * Glue class responsible for connecting the current downloads and {@link OfflineContentProvider}
* thumbnail work to the {@link ThumbnailProvider} via a custon {@link ThumbnailProviderImpl}. * thumbnail work to the {@link ThumbnailProvider} via a custom {@link ThumbnailProviderImpl}.
*/ */
public class ThumbnailRequestGlue implements ThumbnailRequest { public class ThumbnailRequestGlue implements ThumbnailRequest {
private final OfflineContentProviderGlue mProvider; private final OfflineContentProviderGlue mProvider;
...@@ -39,6 +42,11 @@ public class ThumbnailRequestGlue implements ThumbnailRequest { ...@@ -39,6 +42,11 @@ public class ThumbnailRequestGlue implements ThumbnailRequest {
return mItem.filePath; return mItem.filePath;
} }
@Override
public String getMimeType() {
return mItem.mimeType;
}
@Override @Override
public String getContentId() { public String getContentId() {
return mItem.id.id; return mItem.id.id;
...@@ -71,4 +79,4 @@ public class ThumbnailRequestGlue implements ThumbnailRequest { ...@@ -71,4 +79,4 @@ public class ThumbnailRequestGlue implements ThumbnailRequest {
} }
}); });
} }
} }
\ No newline at end of file
...@@ -117,9 +117,7 @@ public final class UiUtils { ...@@ -117,9 +117,7 @@ public final class UiUtils {
public static boolean canHaveThumbnails(OfflineItem item) { public static boolean canHaveThumbnails(OfflineItem item) {
switch (item.filter) { switch (item.filter) {
case OfflineItemFilter.FILTER_PAGE: case OfflineItemFilter.FILTER_PAGE:
// TODO(shaktisahu, xingliu): Remove this after video thumbnail generation pipeline is case OfflineItemFilter.FILTER_VIDEO:
// done.
// case OfflineItemFilter.FILTER_VIDEO:
case OfflineItemFilter.FILTER_IMAGE: case OfflineItemFilter.FILTER_IMAGE:
return true; return true;
default: default:
......
...@@ -178,6 +178,11 @@ public class DownloadItemView extends SelectableItemView<DownloadHistoryItemWrap ...@@ -178,6 +178,11 @@ public class DownloadItemView extends SelectableItemView<DownloadHistoryItemWrap
return mItem == null ? null : mItem.getFilePath(); return mItem == null ? null : mItem.getFilePath();
} }
@Override
public String getMimeType() {
return mItem == null ? null : mItem.getMimeType();
}
@Override @Override
public @Nullable String getContentId() { public @Nullable String getContentId() {
return mItem == null ? "" : mItem.getId(); return mItem == null ? "" : mItem.getId();
......
...@@ -390,5 +390,10 @@ public class ImageFetcher { ...@@ -390,5 +390,10 @@ public class ImageFetcher {
public Promise<Bitmap> getPromise() { public Promise<Bitmap> getPromise() {
return mThumbnailReceivedPromise; return mThumbnailReceivedPromise;
} }
@Override
public String getMimeType() {
return null;
}
} }
} }
...@@ -42,7 +42,7 @@ public class ThumbnailGenerator { ...@@ -42,7 +42,7 @@ public class ThumbnailGenerator {
boolean hasFilePath = !TextUtils.isEmpty(request.getFilePath()); boolean hasFilePath = !TextUtils.isEmpty(request.getFilePath());
assert hasFilePath; assert hasFilePath;
nativeRetrieveThumbnail(getNativeThumbnailGenerator(), request.getContentId(), nativeRetrieveThumbnail(getNativeThumbnailGenerator(), request.getContentId(),
request.getFilePath(), request.getIconSize(), callback); request.getFilePath(), request.getMimeType(), request.getIconSize(), callback);
} }
/** /**
...@@ -80,5 +80,6 @@ public class ThumbnailGenerator { ...@@ -80,5 +80,6 @@ public class ThumbnailGenerator {
private native long nativeInit(); private native long nativeInit();
private native void nativeDestroy(long nativeThumbnailGenerator); private native void nativeDestroy(long nativeThumbnailGenerator);
private native void nativeRetrieveThumbnail(long nativeThumbnailGenerator, String contentId, private native void nativeRetrieveThumbnail(long nativeThumbnailGenerator, String contentId,
String filePath, int thumbnailSize, ThumbnailGeneratorCallback callback); String filePath, String mimeType, int thumbnailSize,
} ThumbnailGeneratorCallback callback);
\ No newline at end of file }
...@@ -20,6 +20,10 @@ public interface ThumbnailProvider { ...@@ -20,6 +20,10 @@ public interface ThumbnailProvider {
@Nullable @Nullable
String getFilePath(); String getFilePath();
/** The mime type of the file. */
@Nullable
String getMimeType();
/** Content ID that uniquely identifies the file. */ /** Content ID that uniquely identifies the file. */
@Nullable @Nullable
String getContentId(); String getContentId();
......
...@@ -63,7 +63,7 @@ public class DownloadMediaParserTest { ...@@ -63,7 +63,7 @@ public class DownloadMediaParserTest {
// The native DownloadMediaParser needs to be created on UI thread. // The native DownloadMediaParser needs to be created on UI thread.
ThreadUtils.runOnUiThreadBlocking(() -> { ThreadUtils.runOnUiThreadBlocking(() -> {
DownloadMediaParserBridge parser = new DownloadMediaParserBridge( DownloadMediaParserBridge parser = new DownloadMediaParserBridge(
mimeType, filePath, mediaFile.length(), (DownloadMediaData mediaData) -> { mimeType, filePath, (DownloadMediaData mediaData) -> {
result.mediaData = mediaData; result.mediaData = mediaData;
result.done = true; result.done = true;
}); });
......
...@@ -63,6 +63,11 @@ public class ThumbnailDiskStorageTest { ...@@ -63,6 +63,11 @@ public class ThumbnailDiskStorageTest {
return null; return null;
} }
@Override
public String getMimeType() {
return null;
}
@Override @Override
public String getContentId() { public String getContentId() {
return mContentId; return mContentId;
......
...@@ -188,6 +188,11 @@ public class ThumbnailProviderImplTest { ...@@ -188,6 +188,11 @@ public class ThumbnailProviderImplTest {
return mTestFilePath; return mTestFilePath;
} }
@Override
public String getMimeType() {
return null;
}
@Override @Override
public @Nullable String getContentId() { public @Nullable String getContentId() {
return "contentId"; // None-null value for ThumbnailProviderImpl to work return "contentId"; // None-null value for ThumbnailProviderImpl to work
......
...@@ -455,6 +455,8 @@ jumbo_split_static_library("browser") { ...@@ -455,6 +455,8 @@ jumbo_split_static_library("browser") {
"download/offline_item_utils.h", "download/offline_item_utils.h",
"download/save_package_file_picker.cc", "download/save_package_file_picker.cc",
"download/save_package_file_picker.h", "download/save_package_file_picker.h",
"download/thumbnail_util.cc",
"download/thumbnail_util.h",
"download/trusted_sources_manager.cc", "download/trusted_sources_manager.cc",
"download/trusted_sources_manager.h", "download/trusted_sources_manager.h",
"download/trusted_sources_manager_win.cc", "download/trusted_sources_manager_win.cc",
......
...@@ -6,9 +6,11 @@ ...@@ -6,9 +6,11 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/files/file.h" #include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/numerics/safe_conversions.h" #include "base/numerics/safe_conversions.h"
#include "base/task/post_task.h" #include "base/task/post_task.h"
#include "base/task/task_traits.h" #include "base/task/task_traits.h"
#include "base/task_runner_util.h"
#include "cc/paint/skia_paint_canvas.h" #include "cc/paint/skia_paint_canvas.h"
#include "chrome/browser/android/download/local_media_data_source_factory.h" #include "chrome/browser/android/download/local_media_data_source_factory.h"
#include "content/public/browser/android/gpu_video_accelerator_factories_provider.h" #include "content/public/browser/android/gpu_video_accelerator_factories_provider.h"
...@@ -38,19 +40,23 @@ bool IsSupportedMediaMimeType(const std::string& mime_type) { ...@@ -38,19 +40,23 @@ bool IsSupportedMediaMimeType(const std::string& mime_type) {
void OnRequestOverlayInfo(bool decoder_requires_restart_for_overlay, void OnRequestOverlayInfo(bool decoder_requires_restart_for_overlay,
const media::ProvideOverlayInfoCB& overlay_info_cb) { const media::ProvideOverlayInfoCB& overlay_info_cb) {
// No android overlay associated with video thumbnail. // No android overlay associated with video thumbnail.
overlay_info_cb.Run(media::OverlayInfo()); if (overlay_info_cb)
overlay_info_cb.Run(media::OverlayInfo());
}
int64_t GetFileSize(const base::FilePath& file_path) {
int64_t size = 0;
if (!base::GetFileSize(file_path, &size))
return -1;
return size;
} }
} // namespace } // namespace
DownloadMediaParser::DownloadMediaParser(int64_t size, DownloadMediaParser::DownloadMediaParser(const std::string& mime_type,
const std::string& mime_type, const base::FilePath& file_path)
const base::FilePath& file_path, : mime_type_(mime_type),
ParseCompleteCB parse_complete_cb)
: size_(size),
mime_type_(mime_type),
file_path_(file_path), file_path_(file_path),
parse_complete_cb_(std::move(parse_complete_cb)),
file_task_runner_( file_task_runner_(
base::CreateSingleThreadTaskRunnerWithTraits({base::MayBlock()})), base::CreateSingleThreadTaskRunnerWithTraits({base::MayBlock()})),
decode_done_(false), decode_done_(false),
...@@ -58,13 +64,30 @@ DownloadMediaParser::DownloadMediaParser(int64_t size, ...@@ -58,13 +64,30 @@ DownloadMediaParser::DownloadMediaParser(int64_t size,
DownloadMediaParser::~DownloadMediaParser() = default; DownloadMediaParser::~DownloadMediaParser() = default;
void DownloadMediaParser::Start() { void DownloadMediaParser::Start(ParseCompleteCB parse_complete_cb) {
parse_complete_cb_ = std::move(parse_complete_cb);
// Only process media mime types. // Only process media mime types.
if (!IsSupportedMediaMimeType(mime_type_)) { if (!IsSupportedMediaMimeType(mime_type_)) {
OnError(); OnError();
return; return;
} }
// Get the size of the file if needed.
base::PostTaskAndReplyWithResult(
file_task_runner_.get(), FROM_HERE,
base::BindOnce(&GetFileSize, file_path_),
base::BindOnce(&DownloadMediaParser::OnReadFileSize,
weak_factory_.GetWeakPtr()));
}
void DownloadMediaParser::OnReadFileSize(int64_t file_size) {
if (file_size < 0) {
OnError();
return;
}
size_ = file_size;
RetrieveMediaParser( RetrieveMediaParser(
content::ServiceManagerConnection::GetForProcess()->GetConnector()); content::ServiceManagerConnection::GetForProcess()->GetConnector());
} }
...@@ -188,6 +211,7 @@ void DownloadMediaParser::DecodeVideoFrame() { ...@@ -188,6 +211,7 @@ void DownloadMediaParser::DecodeVideoFrame() {
decoder_->Start(base::BindOnce(&DownloadMediaParser::OnVideoFrameDecoded, decoder_->Start(base::BindOnce(&DownloadMediaParser::OnVideoFrameDecoded,
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
video_frame_data_.reset();
} }
void DownloadMediaParser::OnVideoFrameDecoded( void DownloadMediaParser::OnVideoFrameDecoded(
......
...@@ -34,9 +34,9 @@ class SkBitmap; ...@@ -34,9 +34,9 @@ class SkBitmap;
// Parse local media files, including media metadata and thumbnails. // Parse local media files, including media metadata and thumbnails.
// Metadata is always parsed in utility process for both audio and video files. // Metadata is always parsed in utility process for both audio and video files.
// //
// For video file, the thumbnail may be poster image in metadata or extracted // For video file, the thumbnail will be the a video key frame. The frame
// video frame. The frame extraction always happens in utility process. The // extraction always happens in utility process. The decoding may happen in
// decoding may happen in utility or GPU process based on video codec. // utility or GPU process based on video codec.
class DownloadMediaParser : public MediaParserProvider, public media::MediaLog { class DownloadMediaParser : public MediaParserProvider, public media::MediaLog {
public: public:
using ParseCompleteCB = using ParseCompleteCB =
...@@ -44,19 +44,19 @@ class DownloadMediaParser : public MediaParserProvider, public media::MediaLog { ...@@ -44,19 +44,19 @@ class DownloadMediaParser : public MediaParserProvider, public media::MediaLog {
chrome::mojom::MediaMetadataPtr media_metadata, chrome::mojom::MediaMetadataPtr media_metadata,
SkBitmap bitmap)>; SkBitmap bitmap)>;
DownloadMediaParser(int64_t size, DownloadMediaParser(const std::string& mime_type,
const std::string& mime_type, const base::FilePath& file_path);
const base::FilePath& file_path,
ParseCompleteCB parse_complete_cb);
~DownloadMediaParser() override; ~DownloadMediaParser() override;
// Parse media metadata in a local file. All file IO will run on // Parse media metadata and thumbnail in a local file. All file IO will run on
// |file_task_runner|. The metadata is parsed in an utility process safely. // |file_task_runner|. The metadata is parsed in an utility process safely.
// The thumbnail is retrieved from GPU process or utility process based on // The thumbnail is retrieved from GPU process or utility process based on
// different codec. // different codec.
void Start(); void Start(ParseCompleteCB parse_complete_cb);
private: private:
void OnReadFileSize(int64_t file_size);
// MediaParserProvider implementation: // MediaParserProvider implementation:
void OnMediaParserCreated() override; void OnMediaParserCreated() override;
void OnConnectionError() override; void OnConnectionError() override;
......
...@@ -47,7 +47,6 @@ jlong JNI_DownloadMediaParserBridge_Init( ...@@ -47,7 +47,6 @@ jlong JNI_DownloadMediaParserBridge_Init(
const base::android::JavaParamRef<jobject>& jcaller, const base::android::JavaParamRef<jobject>& jcaller,
const base::android::JavaParamRef<jstring>& jmime_type, const base::android::JavaParamRef<jstring>& jmime_type,
const base::android::JavaParamRef<jstring>& jfile_path, const base::android::JavaParamRef<jstring>& jfile_path,
jlong jtotal_size,
const base::android::JavaParamRef<jobject>& jcallback) { const base::android::JavaParamRef<jobject>& jcallback) {
base::FilePath file_path( base::FilePath file_path(
base::android::ConvertJavaStringToUTF8(env, jfile_path)); base::android::ConvertJavaStringToUTF8(env, jfile_path));
...@@ -55,22 +54,18 @@ jlong JNI_DownloadMediaParserBridge_Init( ...@@ -55,22 +54,18 @@ jlong JNI_DownloadMediaParserBridge_Init(
base::android::ConvertJavaStringToUTF8(env, jmime_type); base::android::ConvertJavaStringToUTF8(env, jmime_type);
auto* bridge = new DownloadMediaParserBridge( auto* bridge = new DownloadMediaParserBridge(
static_cast<int64_t>(jtotal_size), mime_type, file_path, mime_type, file_path,
base::BindOnce(&OnMediaParsed, base::BindOnce(&OnMediaParsed,
base::android::ScopedJavaGlobalRef<jobject>(jcallback))); base::android::ScopedJavaGlobalRef<jobject>(jcallback)));
return reinterpret_cast<intptr_t>(bridge); return reinterpret_cast<intptr_t>(bridge);
} }
DownloadMediaParserBridge::DownloadMediaParserBridge( DownloadMediaParserBridge::DownloadMediaParserBridge(
int64_t size,
const std::string& mime_type, const std::string& mime_type,
const base::FilePath& file_path, const base::FilePath& file_path,
DownloadMediaParser::ParseCompleteCB parse_complete_cb) DownloadMediaParser::ParseCompleteCB parse_complete_cb)
: parser_(std::make_unique<DownloadMediaParser>( : parser_(std::make_unique<DownloadMediaParser>(mime_type, file_path)),
size, parse_complete_cb_(std::move(parse_complete_cb)) {}
mime_type,
file_path,
std::move(parse_complete_cb))) {}
DownloadMediaParserBridge::~DownloadMediaParserBridge() = default; DownloadMediaParserBridge::~DownloadMediaParserBridge() = default;
...@@ -79,5 +74,5 @@ void DownloadMediaParserBridge::Destory(JNIEnv* env, jobject obj) { ...@@ -79,5 +74,5 @@ void DownloadMediaParserBridge::Destory(JNIEnv* env, jobject obj) {
} }
void DownloadMediaParserBridge::Start(JNIEnv* env, jobject obj) { void DownloadMediaParserBridge::Start(JNIEnv* env, jobject obj) {
parser_->Start(); parser_->Start(std::move(parse_complete_cb_));
} }
...@@ -19,7 +19,6 @@ class DownloadMediaParser; ...@@ -19,7 +19,6 @@ class DownloadMediaParser;
class DownloadMediaParserBridge { class DownloadMediaParserBridge {
public: public:
DownloadMediaParserBridge( DownloadMediaParserBridge(
int64_t size,
const std::string& mime_type, const std::string& mime_type,
const base::FilePath& file_path, const base::FilePath& file_path,
DownloadMediaParser::ParseCompleteCB parse_complete_cb); DownloadMediaParser::ParseCompleteCB parse_complete_cb);
...@@ -31,6 +30,7 @@ class DownloadMediaParserBridge { ...@@ -31,6 +30,7 @@ class DownloadMediaParserBridge {
private: private:
// The media parser that does actual jobs in a sandboxed process. // The media parser that does actual jobs in a sandboxed process.
std::unique_ptr<DownloadMediaParser> parser_; std::unique_ptr<DownloadMediaParser> parser_;
DownloadMediaParser::ParseCompleteCB parse_complete_cb_;
DISALLOW_COPY_AND_ASSIGN(DownloadMediaParserBridge); DISALLOW_COPY_AND_ASSIGN(DownloadMediaParserBridge);
}; };
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#include "base/android/jni_string.h" #include "base/android/jni_string.h"
#include "base/threading/thread_restrictions.h" #include "base/threading/thread_restrictions.h"
#include "chrome/browser/android/download/download_media_parser.h"
#include "chrome/browser/download/thumbnail_util.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "jni/ThumbnailGenerator_jni.h" #include "jni/ThumbnailGenerator_jni.h"
#include "ui/gfx/android/java_bitmap.h" #include "ui/gfx/android/java_bitmap.h"
...@@ -15,6 +17,30 @@ ...@@ -15,6 +17,30 @@
class SkBitmap; class SkBitmap;
using base::android::JavaParamRef; using base::android::JavaParamRef;
using base::android::ScopedJavaGlobalRef;
namespace {
void ForwardJavaCallback(const ScopedJavaGlobalRef<jobject>& java_delegate,
const ScopedJavaGlobalRef<jstring>& content_id,
int icon_size,
const ScopedJavaGlobalRef<jobject>& callback,
SkBitmap thumbnail) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
JNIEnv* env = base::android::AttachCurrentThread();
Java_ThumbnailGenerator_onThumbnailRetrieved(
env, java_delegate, content_id, icon_size,
thumbnail.drawsNothing() ? NULL : gfx::ConvertToJavaBitmap(&thumbnail),
callback);
}
void OnThumbnailScaled(base::OnceCallback<void(SkBitmap)> java_callback,
SkBitmap scaled_thumbnail) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
std::move(java_callback).Run(std::move(scaled_thumbnail));
}
} // namespace
ThumbnailGenerator::ThumbnailGenerator(const JavaParamRef<jobject>& jobj) ThumbnailGenerator::ThumbnailGenerator(const JavaParamRef<jobject>& jobj)
: java_delegate_(jobj), weak_factory_(this) { : java_delegate_(jobj), weak_factory_(this) {
...@@ -29,19 +55,27 @@ void ThumbnailGenerator::Destroy(JNIEnv* env, ...@@ -29,19 +55,27 @@ void ThumbnailGenerator::Destroy(JNIEnv* env,
delete this; delete this;
} }
void ThumbnailGenerator::OnThumbnailRetrieved( void ThumbnailGenerator::OnImageThumbnailRetrieved(
const base::android::ScopedJavaGlobalRef<jstring>& content_id, base::OnceCallback<void(SkBitmap)> java_callback,
int icon_size,
const base::android::ScopedJavaGlobalRef<jobject>& callback,
const SkBitmap& thumbnail) { const SkBitmap& thumbnail) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Send the bitmap back to Java-land. // Send the bitmap back to Java-land.
JNIEnv* env = base::android::AttachCurrentThread(); std::move(java_callback).Run(std::move(thumbnail));
Java_ThumbnailGenerator_onThumbnailRetrieved( }
env, java_delegate_, content_id, icon_size,
thumbnail.drawsNothing() ? NULL : gfx::ConvertToJavaBitmap(&thumbnail), void ThumbnailGenerator::OnVideoThumbnailRetrieved(
callback); base::OnceCallback<void(SkBitmap)> java_callback,
int icon_size,
std::unique_ptr<DownloadMediaParser> parser,
bool success,
chrome::mojom::MediaMetadataPtr media_metadata,
SkBitmap thumbnail) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Scale the bitmap before sending back to Java.
ScaleDownBitmap(icon_size, std::move(thumbnail),
base::BindOnce(&OnThumbnailScaled, std::move(java_callback)));
} }
void ThumbnailGenerator::RetrieveThumbnail( void ThumbnailGenerator::RetrieveThumbnail(
...@@ -49,20 +83,42 @@ void ThumbnailGenerator::RetrieveThumbnail( ...@@ -49,20 +83,42 @@ void ThumbnailGenerator::RetrieveThumbnail(
const JavaParamRef<jobject>& jobj, const JavaParamRef<jobject>& jobj,
const JavaParamRef<jstring>& jcontent_id, const JavaParamRef<jstring>& jcontent_id,
const JavaParamRef<jstring>& jfile_path, const JavaParamRef<jstring>& jfile_path,
const JavaParamRef<jstring>& jmime_type,
jint icon_size, jint icon_size,
const JavaParamRef<jobject>& callback) { const JavaParamRef<jobject>& callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
std::string file_path = base::FilePath file_path = base::FilePath::FromUTF8Unsafe(
base::android::ConvertJavaStringToUTF8(env, jfile_path); base::android::ConvertJavaStringToUTF8(env, jfile_path));
std::string mime_type =
jmime_type.is_null()
? ""
: base::android::ConvertJavaStringToUTF8(env, jmime_type);
// Bind everything passed back to Java.
auto java_callback =
base::BindOnce(&ForwardJavaCallback, java_delegate_,
ScopedJavaGlobalRef<jstring>(jcontent_id), icon_size,
ScopedJavaGlobalRef<jobject>(callback));
// Retrieve video thumbnail.
if (base::StartsWith(mime_type, "video/",
base::CompareCase::INSENSITIVE_ASCII)) {
auto parser = std::make_unique<DownloadMediaParser>(mime_type, file_path);
parser->Start(base::BindOnce(&ThumbnailGenerator::OnVideoThumbnailRetrieved,
weak_factory_.GetWeakPtr(),
std::move(java_callback), icon_size,
std::move(parser)));
return;
}
// Retrieve image thumbnail.
auto request = std::make_unique<ImageThumbnailRequest>( auto request = std::make_unique<ImageThumbnailRequest>(
icon_size, icon_size,
base::BindOnce( base::BindOnce(&ThumbnailGenerator::OnImageThumbnailRetrieved,
&ThumbnailGenerator::OnThumbnailRetrieved, weak_factory_.GetWeakPtr(), weak_factory_.GetWeakPtr(), std::move(java_callback)));
base::android::ScopedJavaGlobalRef<jstring>(jcontent_id), icon_size, request->Start(file_path);
base::android::ScopedJavaGlobalRef<jobject>(callback)));
request->Start(base::FilePath::FromUTF8Unsafe(file_path));
// Dropping ownership of |request| here because it will clean itself up once // Dropping ownership of |request| here because it will clean itself up once
// the started request finishes. // the started request finishes.
......
...@@ -5,11 +5,15 @@ ...@@ -5,11 +5,15 @@
#ifndef CHROME_BROWSER_ANDROID_WIDGET_THUMBNAIL_GENERATOR_H_ #ifndef CHROME_BROWSER_ANDROID_WIDGET_THUMBNAIL_GENERATOR_H_
#define CHROME_BROWSER_ANDROID_WIDGET_THUMBNAIL_GENERATOR_H_ #define CHROME_BROWSER_ANDROID_WIDGET_THUMBNAIL_GENERATOR_H_
#include <memory>
#include <string> #include <string>
#include "base/android/jni_android.h" #include "base/android/jni_android.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "chrome/browser/download/image_thumbnail_request.h" #include "chrome/browser/download/image_thumbnail_request.h"
#include "chrome/services/media_gallery_util/public/mojom/media_parser.mojom.h"
class DownloadMediaParser;
// Kicks off asynchronous pipelines for creating thumbnails for local files. // Kicks off asynchronous pipelines for creating thumbnails for local files.
// The native-side ThumbnailGenerator is owned by the Java-side and can be // The native-side ThumbnailGenerator is owned by the Java-side and can be
...@@ -31,19 +35,29 @@ class ThumbnailGenerator { ...@@ -31,19 +35,29 @@ class ThumbnailGenerator {
const base::android::JavaParamRef<jobject>& jobj, const base::android::JavaParamRef<jobject>& jobj,
const base::android::JavaParamRef<jstring>& jcontent_id, const base::android::JavaParamRef<jstring>& jcontent_id,
const base::android::JavaParamRef<jstring>& jfile_path, const base::android::JavaParamRef<jstring>& jfile_path,
const base::android::JavaParamRef<jstring>& jmime_type,
jint icon_size, jint icon_size,
const base::android::JavaParamRef<jobject>& callback); const base::android::JavaParamRef<jobject>& callback);
private: private:
~ThumbnailGenerator(); ~ThumbnailGenerator();
// Called when the thumbnail is ready. |thumbnail| will be empty on failure. // Called when the image thumbnail is ready. |thumbnail| will be empty on
void OnThumbnailRetrieved( // failure.
const base::android::ScopedJavaGlobalRef<jstring>& content_id, void OnImageThumbnailRetrieved(
int icon_size, base::OnceCallback<void(SkBitmap)> java_callback,
const base::android::ScopedJavaGlobalRef<jobject>& callback,
const SkBitmap& thumbnail); const SkBitmap& thumbnail);
// Called when the video thumbnail is ready. |thumbnail| will be empty on
// failure.
void OnVideoThumbnailRetrieved(
base::OnceCallback<void(SkBitmap)> java_callback,
int icon_size,
std::unique_ptr<DownloadMediaParser> parser,
bool success,
chrome::mojom::MediaMetadataPtr media_metadata,
SkBitmap thumbnail);
// This is a {@link ThumbnailGenerator} Java object. // This is a {@link ThumbnailGenerator} Java object.
base::android::ScopedJavaGlobalRef<jobject> java_delegate_; base::android::ScopedJavaGlobalRef<jobject> java_delegate_;
base::WeakPtrFactory<ThumbnailGenerator> weak_factory_; base::WeakPtrFactory<ThumbnailGenerator> weak_factory_;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/task/post_task.h" #include "base/task/post_task.h"
#include "base/threading/scoped_blocking_call.h" #include "base/threading/scoped_blocking_call.h"
#include "chrome/browser/download/thumbnail_util.h"
#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "skia/ext/image_operations.h" #include "skia/ext/image_operations.h"
...@@ -41,26 +42,6 @@ std::string LoadImageData(const base::FilePath& path) { ...@@ -41,26 +42,6 @@ std::string LoadImageData(const base::FilePath& path) {
return data; return data;
} }
SkBitmap ScaleDownBitmap(int icon_size, const SkBitmap& decoded_image) {
DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if (decoded_image.drawsNothing())
return decoded_image;
// Shrink the image down so that its smallest dimension is equal to or
// smaller than the requested size.
int min_dimension = std::min(decoded_image.width(), decoded_image.height());
if (min_dimension <= icon_size)
return decoded_image;
uint64_t width = static_cast<uint64_t>(decoded_image.width());
uint64_t height = static_cast<uint64_t>(decoded_image.height());
return skia::ImageOperations::Resize(
decoded_image, skia::ImageOperations::RESIZE_BEST,
width * icon_size / min_dimension, height * icon_size / min_dimension);
}
} // namespace } // namespace
ImageThumbnailRequest::ImageThumbnailRequest( ImageThumbnailRequest::ImageThumbnailRequest(
...@@ -87,11 +68,9 @@ void ImageThumbnailRequest::Start(const base::FilePath& path) { ...@@ -87,11 +68,9 @@ void ImageThumbnailRequest::Start(const base::FilePath& path) {
void ImageThumbnailRequest::OnImageDecoded(const SkBitmap& decoded_image) { void ImageThumbnailRequest::OnImageDecoded(const SkBitmap& decoded_image) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
base::PostTaskWithTraitsAndReplyWithResult( ScaleDownBitmap(icon_size_, decoded_image,
FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING}, base::BindOnce(&ImageThumbnailRequest::FinishRequest,
base::BindOnce(&ScaleDownBitmap, icon_size_, decoded_image), weak_ptr_factory_.GetWeakPtr()));
base::BindOnce(&ImageThumbnailRequest::FinishRequest,
weak_ptr_factory_.GetWeakPtr()));
} }
void ImageThumbnailRequest::OnDecodeImageFailed() { void ImageThumbnailRequest::OnDecodeImageFailed() {
...@@ -110,9 +89,10 @@ void ImageThumbnailRequest::OnLoadComplete(const std::string& data) { ...@@ -110,9 +89,10 @@ void ImageThumbnailRequest::OnLoadComplete(const std::string& data) {
ImageDecoder::Start(this, data); ImageDecoder::Start(this, data);
} }
void ImageThumbnailRequest::FinishRequest(const SkBitmap& thumbnail) { void ImageThumbnailRequest::FinishRequest(SkBitmap thumbnail) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, base::PostTaskWithTraits(
base::BindOnce(std::move(callback_), thumbnail)); FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(std::move(callback_), std::move(thumbnail)));
delete this; delete this;
} }
...@@ -33,7 +33,7 @@ class ImageThumbnailRequest : public ImageDecoder::ImageRequest { ...@@ -33,7 +33,7 @@ class ImageThumbnailRequest : public ImageDecoder::ImageRequest {
void OnLoadComplete(const std::string& data); void OnLoadComplete(const std::string& data);
void FinishRequest(const SkBitmap& thumbnail); void FinishRequest(SkBitmap thumbnail);
const int icon_size_; const int icon_size_;
base::OnceCallback<void(const SkBitmap&)> callback_; base::OnceCallback<void(const SkBitmap&)> callback_;
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/download/thumbnail_util.h"
#include "base/logging.h"
#include "base/task/post_task.h"
#include "content/public/browser/browser_thread.h"
#include "skia/ext/image_operations.h"
namespace {
SkBitmap ScaleDownBitmapOnIOThread(int icon_size, SkBitmap bitmap) {
DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if (bitmap.drawsNothing())
return bitmap;
// Shrink the image down so that its smallest dimension is equal to or
// smaller than the requested size.
int min_dimension = std::min(bitmap.width(), bitmap.height());
if (min_dimension <= icon_size)
return bitmap;
uint64_t width = static_cast<uint64_t>(bitmap.width());
uint64_t height = static_cast<uint64_t>(bitmap.height());
return skia::ImageOperations::Resize(
bitmap, skia::ImageOperations::RESIZE_BEST,
width * icon_size / min_dimension, height * icon_size / min_dimension);
}
} // namespace
void ScaleDownBitmap(int icon_size,
const SkBitmap& bitmap,
base::OnceCallback<void(SkBitmap)> callback) {
DCHECK(callback);
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
// Scale down bitmap on another thread.
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING},
base::BindOnce(&ScaleDownBitmapOnIOThread, icon_size, std::move(bitmap)),
std::move(callback));
}
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_DOWNLOAD_THUMBNAIL_UTIL_H_
#define CHROME_BROWSER_DOWNLOAD_THUMBNAIL_UTIL_H_
#include "base/callback.h"
class SkBitmap;
// Scale down the bitmap. The result is returned in the |callback|. The aspect
// ratio is kept. The maximum size of the width or height will be no greater
// than |icon_size|.
void ScaleDownBitmap(int icon_size,
const SkBitmap& bitmap,
base::OnceCallback<void(SkBitmap)> callback);
#endif // CHROME_BROWSER_DOWNLOAD_THUMBNAIL_UTIL_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment