diff options
author | 2019-02-21 14:18:11 +0900 | |
---|---|---|
committer | 2019-02-22 08:47:24 +0000 | |
commit | cb1e896d575891a8984f81e1345306ce63ea336d (patch) | |
tree | 0c9e0a720d2665315ac9b8eb285d9a6d0df4eb60 | |
parent | 944017c840f076ee336c93c1b482c2fd31c20de2 (diff) |
Extract android_media_Utils.cpp as a lib
This is a part of job to cut dependency from libmediandk
to libandroid_runtime. As a LL-NDK, libmediandk desn't have
to depend on libandroid_runtime.
dependency: libmediandk -> libmedia_jni -> libandroid_runtime
Libmediandk calls three utility functions defined in
android_media_Utils.cpp. But these functions are independent
from libandroid_runtime.
By extracting those utility functions into its own shared library
(libmedia_jni_utils), the dependency from libmediandk to
libmedia_jni is cut down.
However, some classes and other functions in android_media_Utils.cpp
are moved into new file, android_media_Streams.cpp since they
depend on libandroid_runtime.
Bug: 124268753
Test: m -j
Change-Id: I1e1ea4bc1ff7022d8d9c42785c8c00e3ca153a50
-rw-r--r-- | media/jni/Android.bp | 33 | ||||
-rw-r--r-- | media/jni/android_media_MediaCodec.cpp | 2 | ||||
-rw-r--r-- | media/jni/android_media_MediaCodecList.cpp | 2 | ||||
-rw-r--r-- | media/jni/android_media_MediaExtractor.cpp | 2 | ||||
-rw-r--r-- | media/jni/android_media_MediaMetadataRetriever.cpp | 3 | ||||
-rw-r--r-- | media/jni/android_media_MediaMuxer.cpp | 2 | ||||
-rw-r--r-- | media/jni/android_media_MediaPlayer.cpp | 2 | ||||
-rw-r--r-- | media/jni/android_media_Streams.cpp | 559 | ||||
-rw-r--r-- | media/jni/android_media_Streams.h | 116 | ||||
-rw-r--r-- | media/jni/android_media_Utils.cpp | 533 | ||||
-rw-r--r-- | media/jni/android_media_Utils.h | 90 | ||||
-rw-r--r-- | media/jni/android_mtp_MtpDatabase.cpp | 2 |
12 files changed, 715 insertions, 631 deletions
diff --git a/media/jni/Android.bp b/media/jni/Android.bp index 8ed265d674a6..9d06a90a7901 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -20,8 +20,8 @@ cc_library_shared { "android_media_MediaScanner.cpp", "android_media_MediaSync.cpp", "android_media_ResampleInputStream.cpp", + "android_media_Streams.cpp", "android_media_SyncParams.cpp", - "android_media_Utils.cpp", "android_mtp_MtpDatabase.cpp", "android_mtp_MtpDevice.cpp", "android_mtp_MtpServer.cpp", @@ -34,6 +34,7 @@ cc_library_shared { "libutils", "libbinder", "libmedia", + "libmedia_jni_utils", "libmedia_omx", "libmediametrics", "libmediadrm", @@ -85,6 +86,36 @@ cc_library_shared { } cc_library_shared { + name: "libmedia_jni_utils", + srcs: [ + "android_media_Utils.cpp", + ], + + shared_libs: [ + "liblog", + "libmedia_omx", + "libnativewindow", + "libui", + "libutils", + "android.hidl.token@1.0-utils", + ], + + include_dirs: [ + "system/media/camera/include", + ], + + export_include_dirs: ["."], + + cflags: [ + "-Wall", + "-Werror", + "-Wno-error=deprecated-declarations", + "-Wunused", + "-Wunreachable-code", + ], +} + +cc_library_shared { name: "libmedia2_jni", srcs: [ diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index f07f1e8fb62b..150b6f918685 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -23,7 +23,7 @@ #include "android_media_MediaCrypto.h" #include "android_media_MediaDescrambler.h" #include "android_media_MediaMetricsJNI.h" -#include "android_media_Utils.h" +#include "android_media_Streams.h" #include "android_runtime/AndroidRuntime.h" #include "android_runtime/android_view_Surface.h" #include "android_util_Binder.h" diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp index 6b8f7457eab9..923d1d253c6e 100644 --- a/media/jni/android_media_MediaCodecList.cpp +++ b/media/jni/android_media_MediaCodecList.cpp @@ -31,7 +31,7 @@ #include "android_runtime/AndroidRuntime.h" #include "jni.h" #include <nativehelper/JNIHelp.h> -#include "android_media_Utils.h" +#include "android_media_Streams.h" using namespace android; diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp index c6b171bdd6d4..f5ae9d0d5d2f 100644 --- a/media/jni/android_media_MediaExtractor.cpp +++ b/media/jni/android_media_MediaExtractor.cpp @@ -22,7 +22,7 @@ #include "android_media_MediaDataSource.h" #include "android_media_MediaExtractor.h" #include "android_media_MediaMetricsJNI.h" -#include "android_media_Utils.h" +#include "android_media_Streams.h" #include "android_os_HwRemoteBinder.h" #include "android_runtime/AndroidRuntime.h" #include "android_runtime/Log.h" diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp index c1226fa89fe4..a4807843d7d8 100644 --- a/media/jni/android_media_MediaMetadataRetriever.cpp +++ b/media/jni/android_media_MediaMetadataRetriever.cpp @@ -18,6 +18,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "MediaMetadataRetrieverJNI" +#include <cmath> #include <assert.h> #include <utils/Log.h> #include <utils/threads.h> @@ -32,7 +33,7 @@ #include <nativehelper/JNIHelp.h> #include "android_runtime/AndroidRuntime.h" #include "android_media_MediaDataSource.h" -#include "android_media_Utils.h" +#include "android_media_Streams.h" #include "android_util_Binder.h" #include "android/graphics/GraphicsJNI.h" diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp index f11452a9d80d..f0aa4c3f1ab6 100644 --- a/media/jni/android_media_MediaMuxer.cpp +++ b/media/jni/android_media_MediaMuxer.cpp @@ -18,7 +18,7 @@ #define LOG_TAG "MediaMuxer-JNI" #include <utils/Log.h> -#include "android_media_Utils.h" +#include "android_media_Streams.h" #include "android_runtime/AndroidRuntime.h" #include "jni.h" #include <nativehelper/JNIHelp.h> diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 35b10817c05c..d24edc7552ae 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -44,7 +44,7 @@ #include "android_media_PlaybackParams.h" #include "android_media_SyncParams.h" #include "android_media_VolumeShaper.h" -#include "android_media_Utils.h" +#include "android_media_Streams.h" #include "android_os_Parcel.h" #include "android_util_Binder.h" diff --git a/media/jni/android_media_Streams.cpp b/media/jni/android_media_Streams.cpp new file mode 100644 index 000000000000..b7cbd97409a2 --- /dev/null +++ b/media/jni/android_media_Streams.cpp @@ -0,0 +1,559 @@ +/* + * Copyright 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// #define LOG_NDEBUG 0 +#define LOG_TAG "AndroidMediaStreams" + +#include <utils/Log.h> +#include "android_media_Streams.h" + +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/ABuffer.h> +#include <media/stagefright/foundation/AMessage.h> + +#include <nativehelper/ScopedLocalRef.h> + +namespace android { + +AssetStream::AssetStream(SkStream* stream) + : mStream(stream), mPosition(0) { +} + +AssetStream::~AssetStream() { +} + +piex::Error AssetStream::GetData( + const size_t offset, const size_t length, std::uint8_t* data) { + // Seek first. + if (mPosition != offset) { + if (!mStream->seek(offset)) { + return piex::Error::kFail; + } + } + + // Read bytes. + size_t size = mStream->read((void*)data, length); + mPosition = offset + size; + + return size == length ? piex::Error::kOk : piex::Error::kFail; +} + +BufferedStream::BufferedStream(SkStream* stream) + : mStream(stream) { +} + +BufferedStream::~BufferedStream() { +} + +piex::Error BufferedStream::GetData( + const size_t offset, const size_t length, std::uint8_t* data) { + // Seek first. + if (offset + length > mStreamBuffer.bytesWritten()) { + size_t sizeToRead = offset + length - mStreamBuffer.bytesWritten(); + if (sizeToRead <= kMinSizeToRead) { + sizeToRead = kMinSizeToRead; + } + + void* tempBuffer = malloc(sizeToRead); + if (tempBuffer == NULL) { + return piex::Error::kFail; + } + + size_t bytesRead = mStream->read(tempBuffer, sizeToRead); + if (bytesRead != sizeToRead) { + free(tempBuffer); + return piex::Error::kFail; + } + mStreamBuffer.write(tempBuffer, bytesRead); + free(tempBuffer); + } + + // Read bytes. + if (mStreamBuffer.read((void*)data, offset, length)) { + return piex::Error::kOk; + } else { + return piex::Error::kFail; + } +} + +FileStream::FileStream(const int fd) + : mPosition(0) { + mFile = fdopen(fd, "r"); + if (mFile == NULL) { + return; + } +} + +FileStream::FileStream(const String8 filename) + : mPosition(0) { + mFile = fopen(filename.string(), "r"); + if (mFile == NULL) { + return; + } +} + +FileStream::~FileStream() { + if (mFile != NULL) { + fclose(mFile); + mFile = NULL; + } +} + +piex::Error FileStream::GetData( + const size_t offset, const size_t length, std::uint8_t* data) { + if (mFile == NULL) { + return piex::Error::kFail; + } + + // Seek first. + if (mPosition != offset) { + fseek(mFile, offset, SEEK_SET); + } + + // Read bytes. + size_t size = fread((void*)data, sizeof(std::uint8_t), length, mFile); + mPosition += size; + + // Handle errors and verify the size. + if (ferror(mFile) || size != length) { + ALOGV("GetData read failed: (offset: %zu, length: %zu)", offset, length); + return piex::Error::kFail; + } + return piex::Error::kOk; +} + +bool FileStream::exists() const { + return mFile != NULL; +} + +bool GetExifFromRawImage( + piex::StreamInterface* stream, const String8& filename, + piex::PreviewImageData& image_data) { + // Reset the PreviewImageData to its default. + image_data = piex::PreviewImageData(); + + if (!piex::IsRaw(stream)) { + // Format not supported. + ALOGV("Format not supported: %s", filename.string()); + return false; + } + + piex::Error err = piex::GetPreviewImageData(stream, &image_data); + + if (err != piex::Error::kOk) { + // The input data seems to be broken. + ALOGV("Raw image not detected: %s (piex error code: %d)", filename.string(), (int32_t)err); + return false; + } + + return true; +} + +bool ConvertKeyValueArraysToKeyedVector( + JNIEnv *env, jobjectArray keys, jobjectArray values, + KeyedVector<String8, String8>* keyedVector) { + + int nKeyValuePairs = 0; + bool failed = false; + if (keys != NULL && values != NULL) { + nKeyValuePairs = env->GetArrayLength(keys); + failed = (nKeyValuePairs != env->GetArrayLength(values)); + } + + if (!failed) { + failed = ((keys != NULL && values == NULL) || + (keys == NULL && values != NULL)); + } + + if (failed) { + ALOGE("keys and values arrays have different length"); + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + return false; + } + + for (int i = 0; i < nKeyValuePairs; ++i) { + // No need to check on the ArrayIndexOutOfBoundsException, since + // it won't happen here. + jstring key = (jstring) env->GetObjectArrayElement(keys, i); + jstring value = (jstring) env->GetObjectArrayElement(values, i); + + const char* keyStr = env->GetStringUTFChars(key, NULL); + if (!keyStr) { // OutOfMemoryError + return false; + } + + const char* valueStr = env->GetStringUTFChars(value, NULL); + if (!valueStr) { // OutOfMemoryError + env->ReleaseStringUTFChars(key, keyStr); + return false; + } + + keyedVector->add(String8(keyStr), String8(valueStr)); + + env->ReleaseStringUTFChars(key, keyStr); + env->ReleaseStringUTFChars(value, valueStr); + env->DeleteLocalRef(key); + env->DeleteLocalRef(value); + } + return true; +} + +static jobject makeIntegerObject(JNIEnv *env, int32_t value) { + ScopedLocalRef<jclass> clazz(env, env->FindClass("java/lang/Integer")); + CHECK(clazz.get() != NULL); + + jmethodID integerConstructID = + env->GetMethodID(clazz.get(), "<init>", "(I)V"); + CHECK(integerConstructID != NULL); + + return env->NewObject(clazz.get(), integerConstructID, value); +} + +static jobject makeLongObject(JNIEnv *env, int64_t value) { + ScopedLocalRef<jclass> clazz(env, env->FindClass("java/lang/Long")); + CHECK(clazz.get() != NULL); + + jmethodID longConstructID = env->GetMethodID(clazz.get(), "<init>", "(J)V"); + CHECK(longConstructID != NULL); + + return env->NewObject(clazz.get(), longConstructID, value); +} + +static jobject makeFloatObject(JNIEnv *env, float value) { + ScopedLocalRef<jclass> clazz(env, env->FindClass("java/lang/Float")); + CHECK(clazz.get() != NULL); + + jmethodID floatConstructID = + env->GetMethodID(clazz.get(), "<init>", "(F)V"); + CHECK(floatConstructID != NULL); + + return env->NewObject(clazz.get(), floatConstructID, value); +} + +static jobject makeByteBufferObject( + JNIEnv *env, const void *data, size_t size) { + jbyteArray byteArrayObj = env->NewByteArray(size); + env->SetByteArrayRegion(byteArrayObj, 0, size, (const jbyte *)data); + + ScopedLocalRef<jclass> clazz(env, env->FindClass("java/nio/ByteBuffer")); + CHECK(clazz.get() != NULL); + + jmethodID byteBufWrapID = + env->GetStaticMethodID( + clazz.get(), "wrap", "([B)Ljava/nio/ByteBuffer;"); + CHECK(byteBufWrapID != NULL); + + jobject byteBufObj = env->CallStaticObjectMethod( + clazz.get(), byteBufWrapID, byteArrayObj); + + env->DeleteLocalRef(byteArrayObj); byteArrayObj = NULL; + + return byteBufObj; +} + +static void SetMapInt32( + JNIEnv *env, jobject hashMapObj, jmethodID hashMapPutID, + const char *key, int32_t value) { + jstring keyObj = env->NewStringUTF(key); + jobject valueObj = makeIntegerObject(env, value); + + env->CallObjectMethod(hashMapObj, hashMapPutID, keyObj, valueObj); + + env->DeleteLocalRef(valueObj); valueObj = NULL; + env->DeleteLocalRef(keyObj); keyObj = NULL; +} + +status_t ConvertMessageToMap( + JNIEnv *env, const sp<AMessage> &msg, jobject *map) { + ScopedLocalRef<jclass> hashMapClazz( + env, env->FindClass("java/util/HashMap")); + + if (hashMapClazz.get() == NULL) { + return -EINVAL; + } + + jmethodID hashMapConstructID = + env->GetMethodID(hashMapClazz.get(), "<init>", "()V"); + + if (hashMapConstructID == NULL) { + return -EINVAL; + } + + jmethodID hashMapPutID = + env->GetMethodID( + hashMapClazz.get(), + "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + + if (hashMapPutID == NULL) { + return -EINVAL; + } + + jobject hashMap = env->NewObject(hashMapClazz.get(), hashMapConstructID); + + for (size_t i = 0; i < msg->countEntries(); ++i) { + AMessage::Type valueType; + const char *key = msg->getEntryNameAt(i, &valueType); + + if (!strncmp(key, "android._", 9)) { + // don't expose private keys (starting with android._) + continue; + } + + jobject valueObj = NULL; + + switch (valueType) { + case AMessage::kTypeInt32: + { + int32_t val; + CHECK(msg->findInt32(key, &val)); + + valueObj = makeIntegerObject(env, val); + break; + } + + case AMessage::kTypeInt64: + { + int64_t val; + CHECK(msg->findInt64(key, &val)); + + valueObj = makeLongObject(env, val); + break; + } + + case AMessage::kTypeFloat: + { + float val; + CHECK(msg->findFloat(key, &val)); + + valueObj = makeFloatObject(env, val); + break; + } + + case AMessage::kTypeString: + { + AString val; + CHECK(msg->findString(key, &val)); + + valueObj = env->NewStringUTF(val.c_str()); + break; + } + + case AMessage::kTypeBuffer: + { + sp<ABuffer> buffer; + CHECK(msg->findBuffer(key, &buffer)); + + valueObj = makeByteBufferObject( + env, buffer->data(), buffer->size()); + break; + } + + case AMessage::kTypeRect: + { + int32_t left, top, right, bottom; + CHECK(msg->findRect(key, &left, &top, &right, &bottom)); + + SetMapInt32( + env, + hashMap, + hashMapPutID, + AStringPrintf("%s-left", key).c_str(), + left); + + SetMapInt32( + env, + hashMap, + hashMapPutID, + AStringPrintf("%s-top", key).c_str(), + top); + + SetMapInt32( + env, + hashMap, + hashMapPutID, + AStringPrintf("%s-right", key).c_str(), + right); + + SetMapInt32( + env, + hashMap, + hashMapPutID, + AStringPrintf("%s-bottom", key).c_str(), + bottom); + break; + } + + default: + break; + } + + if (valueObj != NULL) { + jstring keyObj = env->NewStringUTF(key); + + env->CallObjectMethod(hashMap, hashMapPutID, keyObj, valueObj); + + env->DeleteLocalRef(keyObj); keyObj = NULL; + env->DeleteLocalRef(valueObj); valueObj = NULL; + } + } + + *map = hashMap; + + return OK; +} + +status_t ConvertKeyValueArraysToMessage( + JNIEnv *env, jobjectArray keys, jobjectArray values, + sp<AMessage> *out) { + ScopedLocalRef<jclass> stringClass(env, env->FindClass("java/lang/String")); + CHECK(stringClass.get() != NULL); + ScopedLocalRef<jclass> integerClass(env, env->FindClass("java/lang/Integer")); + CHECK(integerClass.get() != NULL); + ScopedLocalRef<jclass> longClass(env, env->FindClass("java/lang/Long")); + CHECK(longClass.get() != NULL); + ScopedLocalRef<jclass> floatClass(env, env->FindClass("java/lang/Float")); + CHECK(floatClass.get() != NULL); + ScopedLocalRef<jclass> byteBufClass(env, env->FindClass("java/nio/ByteBuffer")); + CHECK(byteBufClass.get() != NULL); + + sp<AMessage> msg = new AMessage; + + jsize numEntries = 0; + + if (keys != NULL) { + if (values == NULL) { + return -EINVAL; + } + + numEntries = env->GetArrayLength(keys); + + if (numEntries != env->GetArrayLength(values)) { + return -EINVAL; + } + } else if (values != NULL) { + return -EINVAL; + } + + for (jsize i = 0; i < numEntries; ++i) { + jobject keyObj = env->GetObjectArrayElement(keys, i); + + if (!env->IsInstanceOf(keyObj, stringClass.get())) { + return -EINVAL; + } + + const char *tmp = env->GetStringUTFChars((jstring)keyObj, NULL); + + if (tmp == NULL) { + return -ENOMEM; + } + + AString key = tmp; + + env->ReleaseStringUTFChars((jstring)keyObj, tmp); + tmp = NULL; + + if (key.startsWith("android._")) { + // don't propagate private keys (starting with android._) + continue; + } + + jobject valueObj = env->GetObjectArrayElement(values, i); + + if (env->IsInstanceOf(valueObj, stringClass.get())) { + const char *value = env->GetStringUTFChars((jstring)valueObj, NULL); + + if (value == NULL) { + return -ENOMEM; + } + + msg->setString(key.c_str(), value); + + env->ReleaseStringUTFChars((jstring)valueObj, value); + value = NULL; + } else if (env->IsInstanceOf(valueObj, integerClass.get())) { + jmethodID intValueID = + env->GetMethodID(integerClass.get(), "intValue", "()I"); + CHECK(intValueID != NULL); + + jint value = env->CallIntMethod(valueObj, intValueID); + + msg->setInt32(key.c_str(), value); + } else if (env->IsInstanceOf(valueObj, longClass.get())) { + jmethodID longValueID = + env->GetMethodID(longClass.get(), "longValue", "()J"); + CHECK(longValueID != NULL); + + jlong value = env->CallLongMethod(valueObj, longValueID); + + msg->setInt64(key.c_str(), value); + } else if (env->IsInstanceOf(valueObj, floatClass.get())) { + jmethodID floatValueID = + env->GetMethodID(floatClass.get(), "floatValue", "()F"); + CHECK(floatValueID != NULL); + + jfloat value = env->CallFloatMethod(valueObj, floatValueID); + + msg->setFloat(key.c_str(), value); + } else if (env->IsInstanceOf(valueObj, byteBufClass.get())) { + jmethodID positionID = + env->GetMethodID(byteBufClass.get(), "position", "()I"); + CHECK(positionID != NULL); + + jmethodID limitID = + env->GetMethodID(byteBufClass.get(), "limit", "()I"); + CHECK(limitID != NULL); + + jint position = env->CallIntMethod(valueObj, positionID); + jint limit = env->CallIntMethod(valueObj, limitID); + + sp<ABuffer> buffer = new ABuffer(limit - position); + + void *data = env->GetDirectBufferAddress(valueObj); + + if (data != NULL) { + memcpy(buffer->data(), + (const uint8_t *)data + position, + buffer->size()); + } else { + jmethodID arrayID = + env->GetMethodID(byteBufClass.get(), "array", "()[B"); + CHECK(arrayID != NULL); + + jbyteArray byteArray = + (jbyteArray)env->CallObjectMethod(valueObj, arrayID); + CHECK(byteArray != NULL); + + env->GetByteArrayRegion( + byteArray, + position, + buffer->size(), + (jbyte *)buffer->data()); + + env->DeleteLocalRef(byteArray); byteArray = NULL; + } + + msg->setBuffer(key.c_str(), buffer); + } + } + + *out = msg; + + return OK; +} + +} // namespace android + diff --git a/media/jni/android_media_Streams.h b/media/jni/android_media_Streams.h new file mode 100644 index 000000000000..d174f9a6650c --- /dev/null +++ b/media/jni/android_media_Streams.h @@ -0,0 +1,116 @@ +/* + * Copyright 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _ANDROID_MEDIA_STREAMS_H_ +#define _ANDROID_MEDIA_STREAMS_H_ + +#include "src/piex_types.h" +#include "src/piex.h" + +#include <jni.h> +#include <nativehelper/JNIHelp.h> +#include <utils/KeyedVector.h> +#include <utils/String8.h> +#include <utils/StrongPointer.h> +#include <SkStream.h> + + +namespace android { + +class AssetStream : public piex::StreamInterface { +private: + SkStream *mStream; + size_t mPosition; + +public: + explicit AssetStream(SkStream* stream); + ~AssetStream(); + + // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer + // provided by the caller, guaranteed to be at least "length" bytes long. + // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at + // 'offset' bytes from the start of the stream. + // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not + // change the contents of 'data'. + piex::Error GetData( + const size_t offset, const size_t length, std::uint8_t* data) override; +}; + +class BufferedStream : public piex::StreamInterface { +private: + SkStream *mStream; + // Growable memory stream + SkDynamicMemoryWStream mStreamBuffer; + + // Minimum size to read on filling the buffer. + const size_t kMinSizeToRead = 8192; + +public: + explicit BufferedStream(SkStream* stream); + ~BufferedStream(); + + // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer + // provided by the caller, guaranteed to be at least "length" bytes long. + // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at + // 'offset' bytes from the start of the stream. + // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not + // change the contents of 'data'. + piex::Error GetData( + const size_t offset, const size_t length, std::uint8_t* data) override; +}; + +class FileStream : public piex::StreamInterface { +private: + FILE *mFile; + size_t mPosition; + +public: + explicit FileStream(const int fd); + explicit FileStream(const String8 filename); + ~FileStream(); + + // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer + // provided by the caller, guaranteed to be at least "length" bytes long. + // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at + // 'offset' bytes from the start of the stream. + // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not + // change the contents of 'data'. + piex::Error GetData( + const size_t offset, const size_t length, std::uint8_t* data) override; + bool exists() const; +}; + +// Reads EXIF metadata from a given raw image via piex. +// And returns true if the operation is successful; otherwise, false. +bool GetExifFromRawImage( + piex::StreamInterface* stream, const String8& filename, piex::PreviewImageData& image_data); + +// Returns true if the conversion is successful; otherwise, false. +bool ConvertKeyValueArraysToKeyedVector( + JNIEnv *env, jobjectArray keys, jobjectArray values, + KeyedVector<String8, String8>* vector); + +struct AMessage; +status_t ConvertMessageToMap( + JNIEnv *env, const sp<AMessage> &msg, jobject *map); + +status_t ConvertKeyValueArraysToMessage( + JNIEnv *env, jobjectArray keys, jobjectArray values, + sp<AMessage> *msg); + +}; // namespace android + +#endif // _ANDROID_MEDIA_STREAMS_H_ diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp index 01baadb2f024..2ef7b9e22b84 100644 --- a/media/jni/android_media_Utils.cpp +++ b/media/jni/android_media_Utils.cpp @@ -21,12 +21,6 @@ #include <utils/Log.h> #include "android_media_Utils.h" -#include <media/stagefright/foundation/ADebug.h> -#include <media/stagefright/foundation/ABuffer.h> -#include <media/stagefright/foundation/AMessage.h> - -#include <nativehelper/ScopedLocalRef.h> - #define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) ) // Must be in sync with the value in HeicCompositeStream.cpp @@ -34,533 +28,6 @@ namespace android { -AssetStream::AssetStream(SkStream* stream) - : mStream(stream), mPosition(0) { -} - -AssetStream::~AssetStream() { -} - -piex::Error AssetStream::GetData( - const size_t offset, const size_t length, std::uint8_t* data) { - // Seek first. - if (mPosition != offset) { - if (!mStream->seek(offset)) { - return piex::Error::kFail; - } - } - - // Read bytes. - size_t size = mStream->read((void*)data, length); - mPosition = offset + size; - - return size == length ? piex::Error::kOk : piex::Error::kFail; -} - -BufferedStream::BufferedStream(SkStream* stream) - : mStream(stream) { -} - -BufferedStream::~BufferedStream() { -} - -piex::Error BufferedStream::GetData( - const size_t offset, const size_t length, std::uint8_t* data) { - // Seek first. - if (offset + length > mStreamBuffer.bytesWritten()) { - size_t sizeToRead = offset + length - mStreamBuffer.bytesWritten(); - if (sizeToRead <= kMinSizeToRead) { - sizeToRead = kMinSizeToRead; - } - - void* tempBuffer = malloc(sizeToRead); - if (tempBuffer == NULL) { - return piex::Error::kFail; - } - - size_t bytesRead = mStream->read(tempBuffer, sizeToRead); - if (bytesRead != sizeToRead) { - free(tempBuffer); - return piex::Error::kFail; - } - mStreamBuffer.write(tempBuffer, bytesRead); - free(tempBuffer); - } - - // Read bytes. - if (mStreamBuffer.read((void*)data, offset, length)) { - return piex::Error::kOk; - } else { - return piex::Error::kFail; - } -} - -FileStream::FileStream(const int fd) - : mPosition(0) { - mFile = fdopen(fd, "r"); - if (mFile == NULL) { - return; - } -} - -FileStream::FileStream(const String8 filename) - : mPosition(0) { - mFile = fopen(filename.string(), "r"); - if (mFile == NULL) { - return; - } -} - -FileStream::~FileStream() { - if (mFile != NULL) { - fclose(mFile); - mFile = NULL; - } -} - -piex::Error FileStream::GetData( - const size_t offset, const size_t length, std::uint8_t* data) { - if (mFile == NULL) { - return piex::Error::kFail; - } - - // Seek first. - if (mPosition != offset) { - fseek(mFile, offset, SEEK_SET); - } - - // Read bytes. - size_t size = fread((void*)data, sizeof(std::uint8_t), length, mFile); - mPosition += size; - - // Handle errors and verify the size. - if (ferror(mFile) || size != length) { - ALOGV("GetData read failed: (offset: %zu, length: %zu)", offset, length); - return piex::Error::kFail; - } - return piex::Error::kOk; -} - -bool FileStream::exists() const { - return mFile != NULL; -} - -bool GetExifFromRawImage( - piex::StreamInterface* stream, const String8& filename, - piex::PreviewImageData& image_data) { - // Reset the PreviewImageData to its default. - image_data = piex::PreviewImageData(); - - if (!piex::IsRaw(stream)) { - // Format not supported. - ALOGV("Format not supported: %s", filename.string()); - return false; - } - - piex::Error err = piex::GetPreviewImageData(stream, &image_data); - - if (err != piex::Error::kOk) { - // The input data seems to be broken. - ALOGV("Raw image not detected: %s (piex error code: %d)", filename.string(), (int32_t)err); - return false; - } - - return true; -} - -bool ConvertKeyValueArraysToKeyedVector( - JNIEnv *env, jobjectArray keys, jobjectArray values, - KeyedVector<String8, String8>* keyedVector) { - - int nKeyValuePairs = 0; - bool failed = false; - if (keys != NULL && values != NULL) { - nKeyValuePairs = env->GetArrayLength(keys); - failed = (nKeyValuePairs != env->GetArrayLength(values)); - } - - if (!failed) { - failed = ((keys != NULL && values == NULL) || - (keys == NULL && values != NULL)); - } - - if (failed) { - ALOGE("keys and values arrays have different length"); - jniThrowException(env, "java/lang/IllegalArgumentException", NULL); - return false; - } - - for (int i = 0; i < nKeyValuePairs; ++i) { - // No need to check on the ArrayIndexOutOfBoundsException, since - // it won't happen here. - jstring key = (jstring) env->GetObjectArrayElement(keys, i); - jstring value = (jstring) env->GetObjectArrayElement(values, i); - - const char* keyStr = env->GetStringUTFChars(key, NULL); - if (!keyStr) { // OutOfMemoryError - return false; - } - - const char* valueStr = env->GetStringUTFChars(value, NULL); - if (!valueStr) { // OutOfMemoryError - env->ReleaseStringUTFChars(key, keyStr); - return false; - } - - keyedVector->add(String8(keyStr), String8(valueStr)); - - env->ReleaseStringUTFChars(key, keyStr); - env->ReleaseStringUTFChars(value, valueStr); - env->DeleteLocalRef(key); - env->DeleteLocalRef(value); - } - return true; -} - -static jobject makeIntegerObject(JNIEnv *env, int32_t value) { - ScopedLocalRef<jclass> clazz(env, env->FindClass("java/lang/Integer")); - CHECK(clazz.get() != NULL); - - jmethodID integerConstructID = - env->GetMethodID(clazz.get(), "<init>", "(I)V"); - CHECK(integerConstructID != NULL); - - return env->NewObject(clazz.get(), integerConstructID, value); -} - -static jobject makeLongObject(JNIEnv *env, int64_t value) { - ScopedLocalRef<jclass> clazz(env, env->FindClass("java/lang/Long")); - CHECK(clazz.get() != NULL); - - jmethodID longConstructID = env->GetMethodID(clazz.get(), "<init>", "(J)V"); - CHECK(longConstructID != NULL); - - return env->NewObject(clazz.get(), longConstructID, value); -} - -static jobject makeFloatObject(JNIEnv *env, float value) { - ScopedLocalRef<jclass> clazz(env, env->FindClass("java/lang/Float")); - CHECK(clazz.get() != NULL); - - jmethodID floatConstructID = - env->GetMethodID(clazz.get(), "<init>", "(F)V"); - CHECK(floatConstructID != NULL); - - return env->NewObject(clazz.get(), floatConstructID, value); -} - -static jobject makeByteBufferObject( - JNIEnv *env, const void *data, size_t size) { - jbyteArray byteArrayObj = env->NewByteArray(size); - env->SetByteArrayRegion(byteArrayObj, 0, size, (const jbyte *)data); - - ScopedLocalRef<jclass> clazz(env, env->FindClass("java/nio/ByteBuffer")); - CHECK(clazz.get() != NULL); - - jmethodID byteBufWrapID = - env->GetStaticMethodID( - clazz.get(), "wrap", "([B)Ljava/nio/ByteBuffer;"); - CHECK(byteBufWrapID != NULL); - - jobject byteBufObj = env->CallStaticObjectMethod( - clazz.get(), byteBufWrapID, byteArrayObj); - - env->DeleteLocalRef(byteArrayObj); byteArrayObj = NULL; - - return byteBufObj; -} - -static void SetMapInt32( - JNIEnv *env, jobject hashMapObj, jmethodID hashMapPutID, - const char *key, int32_t value) { - jstring keyObj = env->NewStringUTF(key); - jobject valueObj = makeIntegerObject(env, value); - - env->CallObjectMethod(hashMapObj, hashMapPutID, keyObj, valueObj); - - env->DeleteLocalRef(valueObj); valueObj = NULL; - env->DeleteLocalRef(keyObj); keyObj = NULL; -} - -status_t ConvertMessageToMap( - JNIEnv *env, const sp<AMessage> &msg, jobject *map) { - ScopedLocalRef<jclass> hashMapClazz( - env, env->FindClass("java/util/HashMap")); - - if (hashMapClazz.get() == NULL) { - return -EINVAL; - } - - jmethodID hashMapConstructID = - env->GetMethodID(hashMapClazz.get(), "<init>", "()V"); - - if (hashMapConstructID == NULL) { - return -EINVAL; - } - - jmethodID hashMapPutID = - env->GetMethodID( - hashMapClazz.get(), - "put", - "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); - - if (hashMapPutID == NULL) { - return -EINVAL; - } - - jobject hashMap = env->NewObject(hashMapClazz.get(), hashMapConstructID); - - for (size_t i = 0; i < msg->countEntries(); ++i) { - AMessage::Type valueType; - const char *key = msg->getEntryNameAt(i, &valueType); - - if (!strncmp(key, "android._", 9)) { - // don't expose private keys (starting with android._) - continue; - } - - jobject valueObj = NULL; - - switch (valueType) { - case AMessage::kTypeInt32: - { - int32_t val; - CHECK(msg->findInt32(key, &val)); - - valueObj = makeIntegerObject(env, val); - break; - } - - case AMessage::kTypeInt64: - { - int64_t val; - CHECK(msg->findInt64(key, &val)); - - valueObj = makeLongObject(env, val); - break; - } - - case AMessage::kTypeFloat: - { - float val; - CHECK(msg->findFloat(key, &val)); - - valueObj = makeFloatObject(env, val); - break; - } - - case AMessage::kTypeString: - { - AString val; - CHECK(msg->findString(key, &val)); - - valueObj = env->NewStringUTF(val.c_str()); - break; - } - - case AMessage::kTypeBuffer: - { - sp<ABuffer> buffer; - CHECK(msg->findBuffer(key, &buffer)); - - valueObj = makeByteBufferObject( - env, buffer->data(), buffer->size()); - break; - } - - case AMessage::kTypeRect: - { - int32_t left, top, right, bottom; - CHECK(msg->findRect(key, &left, &top, &right, &bottom)); - - SetMapInt32( - env, - hashMap, - hashMapPutID, - AStringPrintf("%s-left", key).c_str(), - left); - - SetMapInt32( - env, - hashMap, - hashMapPutID, - AStringPrintf("%s-top", key).c_str(), - top); - - SetMapInt32( - env, - hashMap, - hashMapPutID, - AStringPrintf("%s-right", key).c_str(), - right); - - SetMapInt32( - env, - hashMap, - hashMapPutID, - AStringPrintf("%s-bottom", key).c_str(), - bottom); - break; - } - - default: - break; - } - - if (valueObj != NULL) { - jstring keyObj = env->NewStringUTF(key); - - env->CallObjectMethod(hashMap, hashMapPutID, keyObj, valueObj); - - env->DeleteLocalRef(keyObj); keyObj = NULL; - env->DeleteLocalRef(valueObj); valueObj = NULL; - } - } - - *map = hashMap; - - return OK; -} - -status_t ConvertKeyValueArraysToMessage( - JNIEnv *env, jobjectArray keys, jobjectArray values, - sp<AMessage> *out) { - ScopedLocalRef<jclass> stringClass(env, env->FindClass("java/lang/String")); - CHECK(stringClass.get() != NULL); - ScopedLocalRef<jclass> integerClass(env, env->FindClass("java/lang/Integer")); - CHECK(integerClass.get() != NULL); - ScopedLocalRef<jclass> longClass(env, env->FindClass("java/lang/Long")); - CHECK(longClass.get() != NULL); - ScopedLocalRef<jclass> floatClass(env, env->FindClass("java/lang/Float")); - CHECK(floatClass.get() != NULL); - ScopedLocalRef<jclass> byteBufClass(env, env->FindClass("java/nio/ByteBuffer")); - CHECK(byteBufClass.get() != NULL); - - sp<AMessage> msg = new AMessage; - - jsize numEntries = 0; - - if (keys != NULL) { - if (values == NULL) { - return -EINVAL; - } - - numEntries = env->GetArrayLength(keys); - - if (numEntries != env->GetArrayLength(values)) { - return -EINVAL; - } - } else if (values != NULL) { - return -EINVAL; - } - - for (jsize i = 0; i < numEntries; ++i) { - jobject keyObj = env->GetObjectArrayElement(keys, i); - - if (!env->IsInstanceOf(keyObj, stringClass.get())) { - return -EINVAL; - } - - const char *tmp = env->GetStringUTFChars((jstring)keyObj, NULL); - - if (tmp == NULL) { - return -ENOMEM; - } - - AString key = tmp; - - env->ReleaseStringUTFChars((jstring)keyObj, tmp); - tmp = NULL; - - if (key.startsWith("android._")) { - // don't propagate private keys (starting with android._) - continue; - } - - jobject valueObj = env->GetObjectArrayElement(values, i); - - if (env->IsInstanceOf(valueObj, stringClass.get())) { - const char *value = env->GetStringUTFChars((jstring)valueObj, NULL); - - if (value == NULL) { - return -ENOMEM; - } - - msg->setString(key.c_str(), value); - - env->ReleaseStringUTFChars((jstring)valueObj, value); - value = NULL; - } else if (env->IsInstanceOf(valueObj, integerClass.get())) { - jmethodID intValueID = - env->GetMethodID(integerClass.get(), "intValue", "()I"); - CHECK(intValueID != NULL); - - jint value = env->CallIntMethod(valueObj, intValueID); - - msg->setInt32(key.c_str(), value); - } else if (env->IsInstanceOf(valueObj, longClass.get())) { - jmethodID longValueID = - env->GetMethodID(longClass.get(), "longValue", "()J"); - CHECK(longValueID != NULL); - - jlong value = env->CallLongMethod(valueObj, longValueID); - - msg->setInt64(key.c_str(), value); - } else if (env->IsInstanceOf(valueObj, floatClass.get())) { - jmethodID floatValueID = - env->GetMethodID(floatClass.get(), "floatValue", "()F"); - CHECK(floatValueID != NULL); - - jfloat value = env->CallFloatMethod(valueObj, floatValueID); - - msg->setFloat(key.c_str(), value); - } else if (env->IsInstanceOf(valueObj, byteBufClass.get())) { - jmethodID positionID = - env->GetMethodID(byteBufClass.get(), "position", "()I"); - CHECK(positionID != NULL); - - jmethodID limitID = - env->GetMethodID(byteBufClass.get(), "limit", "()I"); - CHECK(limitID != NULL); - - jint position = env->CallIntMethod(valueObj, positionID); - jint limit = env->CallIntMethod(valueObj, limitID); - - sp<ABuffer> buffer = new ABuffer(limit - position); - - void *data = env->GetDirectBufferAddress(valueObj); - - if (data != NULL) { - memcpy(buffer->data(), - (const uint8_t *)data + position, - buffer->size()); - } else { - jmethodID arrayID = - env->GetMethodID(byteBufClass.get(), "array", "()[B"); - CHECK(arrayID != NULL); - - jbyteArray byteArray = - (jbyteArray)env->CallObjectMethod(valueObj, arrayID); - CHECK(byteArray != NULL); - - env->GetByteArrayRegion( - byteArray, - position, - buffer->size(), - (jbyte *)buffer->data()); - - env->DeleteLocalRef(byteArray); byteArray = NULL; - } - - msg->setBuffer(key.c_str(), buffer); - } - } - - *out = msg; - - return OK; -} - // -----------Utility functions used by ImageReader/Writer JNI----------------- enum { diff --git a/media/jni/android_media_Utils.h b/media/jni/android_media_Utils.h index 19c1b88f78e8..12841c097943 100644 --- a/media/jni/android_media_Utils.h +++ b/media/jni/android_media_Utils.h @@ -17,100 +17,10 @@ #ifndef _ANDROID_MEDIA_UTILS_H_ #define _ANDROID_MEDIA_UTILS_H_ -#include "src/piex_types.h" -#include "src/piex.h" - -#include <android_runtime/AndroidRuntime.h> #include <gui/CpuConsumer.h> -#include <jni.h> -#include <nativehelper/JNIHelp.h> -#include <utils/KeyedVector.h> -#include <utils/String8.h> -#include <SkStream.h> namespace android { -class AssetStream : public piex::StreamInterface { -private: - SkStream *mStream; - size_t mPosition; - -public: - explicit AssetStream(SkStream* stream); - ~AssetStream(); - - // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer - // provided by the caller, guaranteed to be at least "length" bytes long. - // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at - // 'offset' bytes from the start of the stream. - // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not - // change the contents of 'data'. - piex::Error GetData( - const size_t offset, const size_t length, std::uint8_t* data) override; -}; - -class BufferedStream : public piex::StreamInterface { -private: - SkStream *mStream; - // Growable memory stream - SkDynamicMemoryWStream mStreamBuffer; - - // Minimum size to read on filling the buffer. - const size_t kMinSizeToRead = 8192; - -public: - explicit BufferedStream(SkStream* stream); - ~BufferedStream(); - - // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer - // provided by the caller, guaranteed to be at least "length" bytes long. - // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at - // 'offset' bytes from the start of the stream. - // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not - // change the contents of 'data'. - piex::Error GetData( - const size_t offset, const size_t length, std::uint8_t* data) override; -}; - -class FileStream : public piex::StreamInterface { -private: - FILE *mFile; - size_t mPosition; - -public: - explicit FileStream(const int fd); - explicit FileStream(const String8 filename); - ~FileStream(); - - // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer - // provided by the caller, guaranteed to be at least "length" bytes long. - // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at - // 'offset' bytes from the start of the stream. - // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not - // change the contents of 'data'. - piex::Error GetData( - const size_t offset, const size_t length, std::uint8_t* data) override; - bool exists() const; -}; - -// Reads EXIF metadata from a given raw image via piex. -// And returns true if the operation is successful; otherwise, false. -bool GetExifFromRawImage( - piex::StreamInterface* stream, const String8& filename, piex::PreviewImageData& image_data); - -// Returns true if the conversion is successful; otherwise, false. -bool ConvertKeyValueArraysToKeyedVector( - JNIEnv *env, jobjectArray keys, jobjectArray values, - KeyedVector<String8, String8>* vector); - -struct AMessage; -status_t ConvertMessageToMap( - JNIEnv *env, const sp<AMessage> &msg, jobject *map); - -status_t ConvertKeyValueArraysToMessage( - JNIEnv *env, jobjectArray keys, jobjectArray values, - sp<AMessage> *msg); - // -----------Utility functions used by ImageReader/Writer JNI----------------- typedef CpuConsumer::LockedBuffer LockedImage; diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp index 06a7182e4b1d..1f89d86947a1 100644 --- a/media/jni/android_mtp_MtpDatabase.cpp +++ b/media/jni/android_mtp_MtpDatabase.cpp @@ -18,7 +18,7 @@ #include "utils/Log.h" #include "utils/String8.h" -#include "android_media_Utils.h" +#include "android_media_Streams.h" #include "mtp.h" #include "IMtpDatabase.h" #include "MtpDataPacket.h" |