Loading media/java/android/mtp/MtpDatabase.java +48 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.content.IntentFilter; import android.content.SharedPreferences; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.media.ExifInterface; import android.media.MediaScanner; import android.net.Uri; import android.os.BatteryManager; Loading @@ -47,6 +48,7 @@ import dalvik.system.CloseGuard; import com.google.android.collect.Sets; import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; Loading Loading @@ -843,6 +845,52 @@ public class MtpDatabase implements AutoCloseable { return obj.getFormat(); } private boolean getThumbnailInfo(int handle, long[] outLongs) { MtpStorageManager.MtpObject obj = mManager.getObject(handle); if (obj == null) { return false; } String path = obj.getPath().toString(); switch (obj.getFormat()) { case MtpConstants.FORMAT_HEIF: case MtpConstants.FORMAT_EXIF_JPEG: case MtpConstants.FORMAT_JFIF: try { ExifInterface exif = new ExifInterface(path); long[] thumbOffsetAndSize = exif.getThumbnailRange(); outLongs[0] = thumbOffsetAndSize != null ? thumbOffsetAndSize[1] : 0; outLongs[1] = exif.getAttributeInt(ExifInterface.TAG_PIXEL_X_DIMENSION, 0); outLongs[2] = exif.getAttributeInt(ExifInterface.TAG_PIXEL_Y_DIMENSION, 0); return true; } catch (IOException e) { // ignore and fall through } } return false; } private byte[] getThumbnailData(int handle) { MtpStorageManager.MtpObject obj = mManager.getObject(handle); if (obj == null) { return null; } String path = obj.getPath().toString(); switch (obj.getFormat()) { case MtpConstants.FORMAT_HEIF: case MtpConstants.FORMAT_EXIF_JPEG: case MtpConstants.FORMAT_JFIF: try { ExifInterface exif = new ExifInterface(path); return exif.getThumbnail(); } catch (IOException e) { // ignore and fall through } } return null; } private int beginDeleteObject(int handle) { MtpStorageManager.MtpObject obj = mManager.getObject(handle); if (obj == null) { Loading media/jni/Android.bp +0 −1 Original line number Diff line number Diff line Loading @@ -50,7 +50,6 @@ cc_library_shared { "libstagefright_foundation", "libcamera_client", "libmtp", "libexif", "libpiex", "libprocessgroup", "libandroidfw", Loading media/jni/android_mtp_MtpDatabase.cpp +32 −92 Original line number Diff line number Diff line Loading @@ -30,13 +30,6 @@ #include "src/piex_types.h" #include "src/piex.h" extern "C" { #include "libexif/exif-content.h" #include "libexif/exif-data.h" #include "libexif/exif-tag.h" #include "libexif/exif-utils.h" } #include <android_runtime/AndroidRuntime.h> #include <android_runtime/Log.h> #include <jni.h> Loading Loading @@ -70,6 +63,8 @@ static jmethodID method_setDeviceProperty; static jmethodID method_getObjectPropertyList; static jmethodID method_getObjectInfo; static jmethodID method_getObjectFilePath; static jmethodID method_getThumbnailInfo; static jmethodID method_getThumbnailData; static jmethodID method_beginDeleteObject; static jmethodID method_endDeleteObject; static jmethodID method_beginMoveObject; Loading Loading @@ -219,7 +214,7 @@ MtpDatabase::MtpDatabase(JNIEnv *env, jobject client) return; // Already threw. } mIntBuffer = (jintArray)env->NewGlobalRef(intArray); jlongArray longArray = env->NewLongArray(2); jlongArray longArray = env->NewLongArray(3); if (!longArray) { return; // Already threw. } Loading Loading @@ -780,57 +775,6 @@ MtpResponseCode MtpDatabase::getObjectPropertyList(MtpObjectHandle handle, return result; } static void foreachentry(ExifEntry *entry, void* /* user */) { char buf[1024]; ALOGI("entry %x, format %d, size %d: %s", entry->tag, entry->format, entry->size, exif_entry_get_value(entry, buf, sizeof(buf))); } static void foreachcontent(ExifContent *content, void *user) { ALOGI("content %d", exif_content_get_ifd(content)); exif_content_foreach_entry(content, foreachentry, user); } static long getLongFromExifEntry(ExifEntry *e) { ExifByteOrder o = exif_data_get_byte_order(e->parent->parent); return exif_get_long(e->data, o); } static ExifData *getExifFromExtractor(const char *path) { std::unique_ptr<uint8_t[]> exifBuf; ExifData *exifdata = NULL; FILE *fp = fopen (path, "rb"); if (!fp) { ALOGE("failed to open file"); return NULL; } sp<NuMediaExtractor> extractor = new NuMediaExtractor(); fseek(fp, 0L, SEEK_END); if (extractor->setDataSource(fileno(fp), 0, ftell(fp)) != OK) { ALOGE("failed to setDataSource"); fclose(fp); return NULL; } off64_t offset; size_t size; if (extractor->getExifOffsetSize(&offset, &size) != OK) { fclose(fp); return NULL; } exifBuf.reset(new uint8_t[size]); fseek(fp, offset, SEEK_SET); if (fread(exifBuf.get(), 1, size, fp) == size) { exifdata = exif_data_new_from_data(exifBuf.get(), size); } fclose(fp); return exifdata; } MtpResponseCode MtpDatabase::getObjectInfo(MtpObjectHandle handle, MtpObjectInfo& info) { MtpStringBuffer path; Loading Loading @@ -877,26 +821,23 @@ MtpResponseCode MtpDatabase::getObjectInfo(MtpObjectHandle handle, case MTP_FORMAT_EXIF_JPEG: case MTP_FORMAT_HEIF: case MTP_FORMAT_JFIF: { ExifData *exifdata; if (info.mFormat == MTP_FORMAT_HEIF) { exifdata = getExifFromExtractor(path); } else { exifdata = exif_data_new_from_file(path); } if (exifdata) { if ((false)) { exif_data_foreach_content(exifdata, foreachcontent, NULL); } env = AndroidRuntime::getJNIEnv(); if (env->CallBooleanMethod( mDatabase, method_getThumbnailInfo, (jint)handle, mLongBuffer)) { ExifEntry *w = exif_content_get_entry( exifdata->ifd[EXIF_IFD_EXIF], EXIF_TAG_PIXEL_X_DIMENSION); ExifEntry *h = exif_content_get_entry( exifdata->ifd[EXIF_IFD_EXIF], EXIF_TAG_PIXEL_Y_DIMENSION); info.mThumbCompressedSize = exifdata->data ? exifdata->size : 0; jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0); jlong size = longValues[0]; jlong w = longValues[1]; jlong h = longValues[2]; if (size > 0 && size <= UINT32_MAX && w > 0 && w <= UINT32_MAX && h > 0 && h <= UINT32_MAX) { info.mThumbCompressedSize = size; info.mThumbFormat = MTP_FORMAT_EXIF_JPEG; info.mImagePixWidth = w ? getLongFromExifEntry(w) : 0; info.mImagePixHeight = h ? getLongFromExifEntry(h) : 0; exif_data_unref(exifdata); info.mImagePixWidth = w; info.mImagePixHeight = h; } env->ReleaseLongArrayElements(mLongBuffer, longValues, 0); } break; } Loading Loading @@ -941,22 +882,19 @@ void* MtpDatabase::getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) { case MTP_FORMAT_EXIF_JPEG: case MTP_FORMAT_HEIF: case MTP_FORMAT_JFIF: { ExifData *exifdata; if (format == MTP_FORMAT_HEIF) { exifdata = getExifFromExtractor(path); } else { exifdata = exif_data_new_from_file(path); JNIEnv* env = AndroidRuntime::getJNIEnv(); jbyteArray thumbData = (jbyteArray) env->CallObjectMethod( mDatabase, method_getThumbnailData, (jint)handle); if (thumbData == NULL) { return nullptr; } if (exifdata) { if (exifdata->data) { result = malloc(exifdata->size); jsize thumbSize = env->GetArrayLength(thumbData); result = malloc(thumbSize); if (result) { memcpy(result, exifdata->data, exifdata->size); outThumbSize = exifdata->size; } } exif_data_unref(exifdata); env->GetByteArrayRegion(thumbData, 0, thumbSize, (jbyte*)result); outThumbSize = thumbSize; } env->DeleteLocalRef(thumbData); break; } Loading Loading @@ -1388,6 +1326,8 @@ int register_android_mtp_MtpDatabase(JNIEnv *env) GET_METHOD_ID(getObjectPropertyList, clazz, "(IIIII)Landroid/mtp/MtpPropertyList;"); GET_METHOD_ID(getObjectInfo, clazz, "(I[I[C[J)Z"); GET_METHOD_ID(getObjectFilePath, clazz, "(I[C[J)I"); GET_METHOD_ID(getThumbnailInfo, clazz, "(I[J)Z"); GET_METHOD_ID(getThumbnailData, clazz, "(I)[B"); GET_METHOD_ID(beginDeleteObject, clazz, "(I)I"); GET_METHOD_ID(endDeleteObject, clazz, "(IZ)V"); GET_METHOD_ID(beginMoveObject, clazz, "(III)I"); Loading Loading
media/java/android/mtp/MtpDatabase.java +48 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.content.IntentFilter; import android.content.SharedPreferences; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.media.ExifInterface; import android.media.MediaScanner; import android.net.Uri; import android.os.BatteryManager; Loading @@ -47,6 +48,7 @@ import dalvik.system.CloseGuard; import com.google.android.collect.Sets; import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; Loading Loading @@ -843,6 +845,52 @@ public class MtpDatabase implements AutoCloseable { return obj.getFormat(); } private boolean getThumbnailInfo(int handle, long[] outLongs) { MtpStorageManager.MtpObject obj = mManager.getObject(handle); if (obj == null) { return false; } String path = obj.getPath().toString(); switch (obj.getFormat()) { case MtpConstants.FORMAT_HEIF: case MtpConstants.FORMAT_EXIF_JPEG: case MtpConstants.FORMAT_JFIF: try { ExifInterface exif = new ExifInterface(path); long[] thumbOffsetAndSize = exif.getThumbnailRange(); outLongs[0] = thumbOffsetAndSize != null ? thumbOffsetAndSize[1] : 0; outLongs[1] = exif.getAttributeInt(ExifInterface.TAG_PIXEL_X_DIMENSION, 0); outLongs[2] = exif.getAttributeInt(ExifInterface.TAG_PIXEL_Y_DIMENSION, 0); return true; } catch (IOException e) { // ignore and fall through } } return false; } private byte[] getThumbnailData(int handle) { MtpStorageManager.MtpObject obj = mManager.getObject(handle); if (obj == null) { return null; } String path = obj.getPath().toString(); switch (obj.getFormat()) { case MtpConstants.FORMAT_HEIF: case MtpConstants.FORMAT_EXIF_JPEG: case MtpConstants.FORMAT_JFIF: try { ExifInterface exif = new ExifInterface(path); return exif.getThumbnail(); } catch (IOException e) { // ignore and fall through } } return null; } private int beginDeleteObject(int handle) { MtpStorageManager.MtpObject obj = mManager.getObject(handle); if (obj == null) { Loading
media/jni/Android.bp +0 −1 Original line number Diff line number Diff line Loading @@ -50,7 +50,6 @@ cc_library_shared { "libstagefright_foundation", "libcamera_client", "libmtp", "libexif", "libpiex", "libprocessgroup", "libandroidfw", Loading
media/jni/android_mtp_MtpDatabase.cpp +32 −92 Original line number Diff line number Diff line Loading @@ -30,13 +30,6 @@ #include "src/piex_types.h" #include "src/piex.h" extern "C" { #include "libexif/exif-content.h" #include "libexif/exif-data.h" #include "libexif/exif-tag.h" #include "libexif/exif-utils.h" } #include <android_runtime/AndroidRuntime.h> #include <android_runtime/Log.h> #include <jni.h> Loading Loading @@ -70,6 +63,8 @@ static jmethodID method_setDeviceProperty; static jmethodID method_getObjectPropertyList; static jmethodID method_getObjectInfo; static jmethodID method_getObjectFilePath; static jmethodID method_getThumbnailInfo; static jmethodID method_getThumbnailData; static jmethodID method_beginDeleteObject; static jmethodID method_endDeleteObject; static jmethodID method_beginMoveObject; Loading Loading @@ -219,7 +214,7 @@ MtpDatabase::MtpDatabase(JNIEnv *env, jobject client) return; // Already threw. } mIntBuffer = (jintArray)env->NewGlobalRef(intArray); jlongArray longArray = env->NewLongArray(2); jlongArray longArray = env->NewLongArray(3); if (!longArray) { return; // Already threw. } Loading Loading @@ -780,57 +775,6 @@ MtpResponseCode MtpDatabase::getObjectPropertyList(MtpObjectHandle handle, return result; } static void foreachentry(ExifEntry *entry, void* /* user */) { char buf[1024]; ALOGI("entry %x, format %d, size %d: %s", entry->tag, entry->format, entry->size, exif_entry_get_value(entry, buf, sizeof(buf))); } static void foreachcontent(ExifContent *content, void *user) { ALOGI("content %d", exif_content_get_ifd(content)); exif_content_foreach_entry(content, foreachentry, user); } static long getLongFromExifEntry(ExifEntry *e) { ExifByteOrder o = exif_data_get_byte_order(e->parent->parent); return exif_get_long(e->data, o); } static ExifData *getExifFromExtractor(const char *path) { std::unique_ptr<uint8_t[]> exifBuf; ExifData *exifdata = NULL; FILE *fp = fopen (path, "rb"); if (!fp) { ALOGE("failed to open file"); return NULL; } sp<NuMediaExtractor> extractor = new NuMediaExtractor(); fseek(fp, 0L, SEEK_END); if (extractor->setDataSource(fileno(fp), 0, ftell(fp)) != OK) { ALOGE("failed to setDataSource"); fclose(fp); return NULL; } off64_t offset; size_t size; if (extractor->getExifOffsetSize(&offset, &size) != OK) { fclose(fp); return NULL; } exifBuf.reset(new uint8_t[size]); fseek(fp, offset, SEEK_SET); if (fread(exifBuf.get(), 1, size, fp) == size) { exifdata = exif_data_new_from_data(exifBuf.get(), size); } fclose(fp); return exifdata; } MtpResponseCode MtpDatabase::getObjectInfo(MtpObjectHandle handle, MtpObjectInfo& info) { MtpStringBuffer path; Loading Loading @@ -877,26 +821,23 @@ MtpResponseCode MtpDatabase::getObjectInfo(MtpObjectHandle handle, case MTP_FORMAT_EXIF_JPEG: case MTP_FORMAT_HEIF: case MTP_FORMAT_JFIF: { ExifData *exifdata; if (info.mFormat == MTP_FORMAT_HEIF) { exifdata = getExifFromExtractor(path); } else { exifdata = exif_data_new_from_file(path); } if (exifdata) { if ((false)) { exif_data_foreach_content(exifdata, foreachcontent, NULL); } env = AndroidRuntime::getJNIEnv(); if (env->CallBooleanMethod( mDatabase, method_getThumbnailInfo, (jint)handle, mLongBuffer)) { ExifEntry *w = exif_content_get_entry( exifdata->ifd[EXIF_IFD_EXIF], EXIF_TAG_PIXEL_X_DIMENSION); ExifEntry *h = exif_content_get_entry( exifdata->ifd[EXIF_IFD_EXIF], EXIF_TAG_PIXEL_Y_DIMENSION); info.mThumbCompressedSize = exifdata->data ? exifdata->size : 0; jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0); jlong size = longValues[0]; jlong w = longValues[1]; jlong h = longValues[2]; if (size > 0 && size <= UINT32_MAX && w > 0 && w <= UINT32_MAX && h > 0 && h <= UINT32_MAX) { info.mThumbCompressedSize = size; info.mThumbFormat = MTP_FORMAT_EXIF_JPEG; info.mImagePixWidth = w ? getLongFromExifEntry(w) : 0; info.mImagePixHeight = h ? getLongFromExifEntry(h) : 0; exif_data_unref(exifdata); info.mImagePixWidth = w; info.mImagePixHeight = h; } env->ReleaseLongArrayElements(mLongBuffer, longValues, 0); } break; } Loading Loading @@ -941,22 +882,19 @@ void* MtpDatabase::getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) { case MTP_FORMAT_EXIF_JPEG: case MTP_FORMAT_HEIF: case MTP_FORMAT_JFIF: { ExifData *exifdata; if (format == MTP_FORMAT_HEIF) { exifdata = getExifFromExtractor(path); } else { exifdata = exif_data_new_from_file(path); JNIEnv* env = AndroidRuntime::getJNIEnv(); jbyteArray thumbData = (jbyteArray) env->CallObjectMethod( mDatabase, method_getThumbnailData, (jint)handle); if (thumbData == NULL) { return nullptr; } if (exifdata) { if (exifdata->data) { result = malloc(exifdata->size); jsize thumbSize = env->GetArrayLength(thumbData); result = malloc(thumbSize); if (result) { memcpy(result, exifdata->data, exifdata->size); outThumbSize = exifdata->size; } } exif_data_unref(exifdata); env->GetByteArrayRegion(thumbData, 0, thumbSize, (jbyte*)result); outThumbSize = thumbSize; } env->DeleteLocalRef(thumbData); break; } Loading Loading @@ -1388,6 +1326,8 @@ int register_android_mtp_MtpDatabase(JNIEnv *env) GET_METHOD_ID(getObjectPropertyList, clazz, "(IIIII)Landroid/mtp/MtpPropertyList;"); GET_METHOD_ID(getObjectInfo, clazz, "(I[I[C[J)Z"); GET_METHOD_ID(getObjectFilePath, clazz, "(I[C[J)I"); GET_METHOD_ID(getThumbnailInfo, clazz, "(I[J)Z"); GET_METHOD_ID(getThumbnailData, clazz, "(I)[B"); GET_METHOD_ID(beginDeleteObject, clazz, "(I)I"); GET_METHOD_ID(endDeleteObject, clazz, "(IZ)V"); GET_METHOD_ID(beginMoveObject, clazz, "(III)I"); Loading