summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Lockwood <lockwood@android.com>2011-04-24 18:40:17 -0700
committerMike Lockwood <lockwood@android.com>2011-04-25 17:40:33 -0700
commitc89f22242b955ae748765b3465b819b40f70ee5f (patch)
treee6eb68d7849ee6954b0b309b480b79ac93c1893f
parent466e3a22db283958a1da71cc60a23ce3976a3659 (diff)
downloadframeworks_base-c89f22242b955ae748765b3465b819b40f70ee5f.zip
frameworks_base-c89f22242b955ae748765b3465b819b40f70ee5f.tar.gz
frameworks_base-c89f22242b955ae748765b3465b819b40f70ee5f.tar.bz2
MTP: Implement GetThumb command
This allows the PC to access thumbnails in JPEG files over MTP/PTP Bug: 3219495 Change-Id: I4964f8b4826dffb7f0f77464ec91bd2e97a2f007 Signed-off-by: Mike Lockwood <lockwood@android.com>
-rw-r--r--media/jni/Android.mk4
-rw-r--r--media/jni/android_mtp_MtpDatabase.cpp63
-rw-r--r--media/mtp/MtpDataPacket.cpp10
-rw-r--r--media/mtp/MtpDataPacket.h1
-rw-r--r--media/mtp/MtpDatabase.h2
-rw-r--r--media/mtp/MtpServer.cpp21
-rw-r--r--media/mtp/MtpServer.h1
7 files changed, 100 insertions, 2 deletions
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 4fd4147..77cedd5 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -27,9 +27,11 @@ LOCAL_SHARED_LIBRARIES := \
libcamera_client \
libsqlite \
libmtp \
- libusbhost
+ libusbhost \
+ libexif
LOCAL_C_INCLUDES += \
+ external/jhead \
external/tremor/Tremor \
frameworks/base/core/jni \
frameworks/base/media/libmedia \
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 585cd30..0f3c063 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -35,6 +35,10 @@
#include "MtpUtils.h"
#include "mtp.h"
+extern "C" {
+#include "jhead.h"
+}
+
using namespace android;
// ----------------------------------------------------------------------------
@@ -141,6 +145,8 @@ public:
virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle,
MtpObjectInfo& info);
+ virtual void* getThumbnail(MtpObjectHandle handle, size_t& outThumbSize);
+
virtual MtpResponseCode getObjectFilePath(MtpObjectHandle handle,
MtpString& outFilePath,
int64_t& outFileLength,
@@ -776,10 +782,67 @@ MtpResponseCode MyMtpDatabase::getObjectInfo(MtpObjectHandle handle,
info.mName = strdup((const char *)temp);
env->ReleaseCharArrayElements(mStringBuffer, str, 0);
+ // read EXIF data for thumbnail information
+ if (info.mFormat == MTP_FORMAT_EXIF_JPEG || info.mFormat == MTP_FORMAT_JFIF) {
+ MtpString path;
+ int64_t length;
+ MtpObjectFormat format;
+ if (getObjectFilePath(handle, path, length, format) == MTP_RESPONSE_OK) {
+ ResetJpgfile();
+ // Start with an empty image information structure.
+ memset(&ImageInfo, 0, sizeof(ImageInfo));
+ ImageInfo.FlashUsed = -1;
+ ImageInfo.MeteringMode = -1;
+ ImageInfo.Whitebalance = -1;
+ strncpy(ImageInfo.FileName, (const char *)path, PATH_MAX);
+ if (ReadJpegFile((const char*)path, READ_METADATA)) {
+ Section_t* section = FindSection(M_EXIF);
+ if (section) {
+ info.mThumbCompressedSize = ImageInfo.ThumbnailSize;
+ info.mThumbFormat = MTP_FORMAT_EXIF_JPEG;
+ info.mImagePixWidth = ImageInfo.Width;
+ info.mImagePixHeight = ImageInfo.Height;
+ }
+ }
+ DiscardData();
+ }
+ }
+
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return MTP_RESPONSE_OK;
}
+void* MyMtpDatabase::getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) {
+ MtpString path;
+ int64_t length;
+ MtpObjectFormat format;
+ void* result = NULL;
+ outThumbSize = 0;
+
+ if (getObjectFilePath(handle, path, length, format) == MTP_RESPONSE_OK
+ && (format == MTP_FORMAT_EXIF_JPEG || format == MTP_FORMAT_JFIF)) {
+ ResetJpgfile();
+ // Start with an empty image information structure.
+ memset(&ImageInfo, 0, sizeof(ImageInfo));
+ ImageInfo.FlashUsed = -1;
+ ImageInfo.MeteringMode = -1;
+ ImageInfo.Whitebalance = -1;
+ strncpy(ImageInfo.FileName, (const char *)path, PATH_MAX);
+ if (ReadJpegFile((const char*)path, READ_METADATA)) {
+ Section_t* section = FindSection(M_EXIF);
+ if (section) {
+ outThumbSize = ImageInfo.ThumbnailSize;
+ result = malloc(outThumbSize);
+ if (result)
+ memcpy(result, section->Data + ImageInfo.ThumbnailOffset + 8, outThumbSize);
+ }
+ DiscardData();
+ }
+ }
+
+ return result;
+}
+
MtpResponseCode MyMtpDatabase::getObjectFilePath(MtpObjectHandle handle,
MtpString& outFilePath,
int64_t& outFileLength,
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index 0b0c80d..817eac0 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -388,6 +388,16 @@ int MtpDataPacket::writeDataHeader(int fd, uint32_t length) {
int ret = ::write(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
return (ret < 0 ? ret : 0);
}
+
+int MtpDataPacket::writeData(int fd, void* data, uint32_t length) {
+ MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, length + MTP_CONTAINER_HEADER_SIZE);
+ MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
+ int ret = ::write(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
+ if (ret == MTP_CONTAINER_HEADER_SIZE)
+ ret = ::write(fd, data, length);
+ return (ret < 0 ? ret : 0);
+}
+
#endif // MTP_DEVICE
#ifdef MTP_HOST
diff --git a/media/mtp/MtpDataPacket.h b/media/mtp/MtpDataPacket.h
index 577cea1..8a08948 100644
--- a/media/mtp/MtpDataPacket.h
+++ b/media/mtp/MtpDataPacket.h
@@ -100,6 +100,7 @@ public:
// write our data to the given file descriptor
int write(int fd);
int writeDataHeader(int fd, uint32_t length);
+ int writeData(int fd, void* data, uint32_t length);
#endif
#ifdef MTP_HOST
diff --git a/media/mtp/MtpDatabase.h b/media/mtp/MtpDatabase.h
index d7bde00..4e6ac7a 100644
--- a/media/mtp/MtpDatabase.h
+++ b/media/mtp/MtpDatabase.h
@@ -84,6 +84,8 @@ public:
virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle,
MtpObjectInfo& info) = 0;
+ virtual void* getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) = 0;
+
virtual MtpResponseCode getObjectFilePath(MtpObjectHandle handle,
MtpString& outFilePath,
int64_t& outFileLength,
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index b744b5b..4a8fd3e 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -50,7 +50,7 @@ static const MtpOperationCode kSupportedOperationCodes[] = {
MTP_OPERATION_GET_OBJECT_HANDLES,
MTP_OPERATION_GET_OBJECT_INFO,
MTP_OPERATION_GET_OBJECT,
-// MTP_OPERATION_GET_THUMB,
+ MTP_OPERATION_GET_THUMB,
MTP_OPERATION_DELETE_OBJECT,
MTP_OPERATION_SEND_OBJECT_INFO,
MTP_OPERATION_SEND_OBJECT,
@@ -370,6 +370,9 @@ bool MtpServer::handleRequest() {
case MTP_OPERATION_GET_OBJECT:
response = doGetObject();
break;
+ case MTP_OPERATION_GET_THUMB:
+ response = doGetThumb();
+ break;
case MTP_OPERATION_GET_PARTIAL_OBJECT:
case MTP_OPERATION_GET_PARTIAL_OBJECT_64:
response = doGetPartialObject(operation);
@@ -736,6 +739,22 @@ MtpResponseCode MtpServer::doGetObject() {
return MTP_RESPONSE_OK;
}
+MtpResponseCode MtpServer::doGetThumb() {
+ MtpObjectHandle handle = mRequest.getParameter(1);
+ size_t thumbSize;
+ void* thumb = mDatabase->getThumbnail(handle, thumbSize);
+ if (thumb) {
+ // send data
+ mData.setOperationCode(mRequest.getOperationCode());
+ mData.setTransactionID(mRequest.getTransactionID());
+ mData.writeData(mFD, thumb, thumbSize);
+ free(thumb);
+ return MTP_RESPONSE_OK;
+ } else {
+ return MTP_RESPONSE_GENERAL_ERROR;
+ }
+}
+
MtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) {
if (!hasStorage())
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index b06eb28..859a18e 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -133,6 +133,7 @@ private:
MtpResponseCode doGetObjectPropList();
MtpResponseCode doGetObjectInfo();
MtpResponseCode doGetObject();
+ MtpResponseCode doGetThumb();
MtpResponseCode doGetPartialObject(MtpOperationCode operation);
MtpResponseCode doSendObjectInfo();
MtpResponseCode doSendObject();