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 \
|
||||
libsqlite \
|
||||
libmtp \
|
||||
libusbhost
|
||||
libusbhost \
|
||||
libexif
|
||||
|
||||
LOCAL_C_INCLUDES += \
|
||||
external/jhead \
|
||||
external/tremor/Tremor \
|
||||
frameworks/base/core/jni \
|
||||
frameworks/base/media/libmedia \
|
||||
|
||||
@@ -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,
|
||||
@@ -778,10 +784,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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -133,6 +133,7 @@ private:
|
||||
MtpResponseCode doGetObjectPropList();
|
||||
MtpResponseCode doGetObjectInfo();
|
||||
MtpResponseCode doGetObject();
|
||||
MtpResponseCode doGetThumb();
|
||||
MtpResponseCode doGetPartialObject(MtpOperationCode operation);
|
||||
MtpResponseCode doSendObjectInfo();
|
||||
MtpResponseCode doSendObject();
|
||||
|
||||
Reference in New Issue
Block a user