DO NOT MERGE MTP: Implement GetThumb command
This allows the PC to access thumbnails in JPEG files over MTP/PTP Bug: 3219495 Change-Id: I565be1fb84e8a204f2be11342b5b952e8965afdf Signed-off-by: Mike Lockwood <lockwood@android.com>
This commit is contained in:
@@ -27,9 +27,11 @@ LOCAL_SHARED_LIBRARIES := \
|
|||||||
libcamera_client \
|
libcamera_client \
|
||||||
libsqlite \
|
libsqlite \
|
||||||
libmtp \
|
libmtp \
|
||||||
libusbhost
|
libusbhost \
|
||||||
|
libexif
|
||||||
|
|
||||||
LOCAL_C_INCLUDES += \
|
LOCAL_C_INCLUDES += \
|
||||||
|
external/jhead \
|
||||||
external/tremor/Tremor \
|
external/tremor/Tremor \
|
||||||
frameworks/base/core/jni \
|
frameworks/base/core/jni \
|
||||||
frameworks/base/media/libmedia \
|
frameworks/base/media/libmedia \
|
||||||
|
|||||||
@@ -35,6 +35,10 @@
|
|||||||
#include "MtpUtils.h"
|
#include "MtpUtils.h"
|
||||||
#include "mtp.h"
|
#include "mtp.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "jhead.h"
|
||||||
|
}
|
||||||
|
|
||||||
using namespace android;
|
using namespace android;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@@ -141,6 +145,8 @@ public:
|
|||||||
virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle,
|
virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle,
|
||||||
MtpObjectInfo& info);
|
MtpObjectInfo& info);
|
||||||
|
|
||||||
|
virtual void* getThumbnail(MtpObjectHandle handle, size_t& outThumbSize);
|
||||||
|
|
||||||
virtual MtpResponseCode getObjectFilePath(MtpObjectHandle handle,
|
virtual MtpResponseCode getObjectFilePath(MtpObjectHandle handle,
|
||||||
MtpString& outFilePath,
|
MtpString& outFilePath,
|
||||||
int64_t& outFileLength,
|
int64_t& outFileLength,
|
||||||
@@ -778,10 +784,67 @@ MtpResponseCode MyMtpDatabase::getObjectInfo(MtpObjectHandle handle,
|
|||||||
info.mName = strdup((const char *)temp);
|
info.mName = strdup((const char *)temp);
|
||||||
env->ReleaseCharArrayElements(mStringBuffer, str, 0);
|
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__);
|
checkAndClearExceptionFromCallback(env, __FUNCTION__);
|
||||||
return MTP_RESPONSE_OK;
|
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,
|
MtpResponseCode MyMtpDatabase::getObjectFilePath(MtpObjectHandle handle,
|
||||||
MtpString& outFilePath,
|
MtpString& outFilePath,
|
||||||
int64_t& outFileLength,
|
int64_t& outFileLength,
|
||||||
|
|||||||
@@ -388,6 +388,16 @@ int MtpDataPacket::writeDataHeader(int fd, uint32_t length) {
|
|||||||
int ret = ::write(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
|
int ret = ::write(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
|
||||||
return (ret < 0 ? ret : 0);
|
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
|
#endif // MTP_DEVICE
|
||||||
|
|
||||||
#ifdef MTP_HOST
|
#ifdef MTP_HOST
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ public:
|
|||||||
// write our data to the given file descriptor
|
// write our data to the given file descriptor
|
||||||
int write(int fd);
|
int write(int fd);
|
||||||
int writeDataHeader(int fd, uint32_t length);
|
int writeDataHeader(int fd, uint32_t length);
|
||||||
|
int writeData(int fd, void* data, uint32_t length);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MTP_HOST
|
#ifdef MTP_HOST
|
||||||
|
|||||||
@@ -84,6 +84,8 @@ public:
|
|||||||
virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle,
|
virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle,
|
||||||
MtpObjectInfo& info) = 0;
|
MtpObjectInfo& info) = 0;
|
||||||
|
|
||||||
|
virtual void* getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) = 0;
|
||||||
|
|
||||||
virtual MtpResponseCode getObjectFilePath(MtpObjectHandle handle,
|
virtual MtpResponseCode getObjectFilePath(MtpObjectHandle handle,
|
||||||
MtpString& outFilePath,
|
MtpString& outFilePath,
|
||||||
int64_t& outFileLength,
|
int64_t& outFileLength,
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ static const MtpOperationCode kSupportedOperationCodes[] = {
|
|||||||
MTP_OPERATION_GET_OBJECT_HANDLES,
|
MTP_OPERATION_GET_OBJECT_HANDLES,
|
||||||
MTP_OPERATION_GET_OBJECT_INFO,
|
MTP_OPERATION_GET_OBJECT_INFO,
|
||||||
MTP_OPERATION_GET_OBJECT,
|
MTP_OPERATION_GET_OBJECT,
|
||||||
// MTP_OPERATION_GET_THUMB,
|
MTP_OPERATION_GET_THUMB,
|
||||||
MTP_OPERATION_DELETE_OBJECT,
|
MTP_OPERATION_DELETE_OBJECT,
|
||||||
MTP_OPERATION_SEND_OBJECT_INFO,
|
MTP_OPERATION_SEND_OBJECT_INFO,
|
||||||
MTP_OPERATION_SEND_OBJECT,
|
MTP_OPERATION_SEND_OBJECT,
|
||||||
@@ -370,6 +370,9 @@ bool MtpServer::handleRequest() {
|
|||||||
case MTP_OPERATION_GET_OBJECT:
|
case MTP_OPERATION_GET_OBJECT:
|
||||||
response = doGetObject();
|
response = doGetObject();
|
||||||
break;
|
break;
|
||||||
|
case MTP_OPERATION_GET_THUMB:
|
||||||
|
response = doGetThumb();
|
||||||
|
break;
|
||||||
case MTP_OPERATION_GET_PARTIAL_OBJECT:
|
case MTP_OPERATION_GET_PARTIAL_OBJECT:
|
||||||
case MTP_OPERATION_GET_PARTIAL_OBJECT_64:
|
case MTP_OPERATION_GET_PARTIAL_OBJECT_64:
|
||||||
response = doGetPartialObject(operation);
|
response = doGetPartialObject(operation);
|
||||||
@@ -736,6 +739,22 @@ MtpResponseCode MtpServer::doGetObject() {
|
|||||||
return MTP_RESPONSE_OK;
|
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) {
|
MtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) {
|
||||||
if (!hasStorage())
|
if (!hasStorage())
|
||||||
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
|
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ private:
|
|||||||
MtpResponseCode doGetObjectPropList();
|
MtpResponseCode doGetObjectPropList();
|
||||||
MtpResponseCode doGetObjectInfo();
|
MtpResponseCode doGetObjectInfo();
|
||||||
MtpResponseCode doGetObject();
|
MtpResponseCode doGetObject();
|
||||||
|
MtpResponseCode doGetThumb();
|
||||||
MtpResponseCode doGetPartialObject(MtpOperationCode operation);
|
MtpResponseCode doGetPartialObject(MtpOperationCode operation);
|
||||||
MtpResponseCode doSendObjectInfo();
|
MtpResponseCode doSendObjectInfo();
|
||||||
MtpResponseCode doSendObject();
|
MtpResponseCode doSendObject();
|
||||||
|
|||||||
Reference in New Issue
Block a user