android_media_MediaDataSource.cpp revision cad52fe423734c12aea2b8e90a2c15952777b536
1/* 2 * Copyright 2015, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17//#define LOG_NDEBUG 0 18#define LOG_TAG "JMediaDataSource-JNI" 19#include <utils/Log.h> 20 21#include "android_media_MediaDataSource.h" 22 23#include "android_runtime/AndroidRuntime.h" 24#include "android_runtime/Log.h" 25#include "jni.h" 26#include "JNIHelp.h" 27 28#include <binder/MemoryDealer.h> 29#include <drm/drm_framework_common.h> 30#include <media/stagefright/foundation/ADebug.h> 31#include <nativehelper/ScopedLocalRef.h> 32 33namespace android { 34 35JMediaDataSource::JMediaDataSource(JNIEnv* env, jobject source) 36 : mJavaObjStatus(OK), mSizeIsCached(false), mCachedSize(0), mMemory(NULL) { 37 mMediaDataSourceObj = env->NewGlobalRef(source); 38 CHECK(mMediaDataSourceObj != NULL); 39 40 ScopedLocalRef<jclass> mediaDataSourceClass(env, env->GetObjectClass(mMediaDataSourceObj)); 41 CHECK(mediaDataSourceClass.get() != NULL); 42 43 mReadMethod = env->GetMethodID(mediaDataSourceClass.get(), "readAt", "(J[BII)I"); 44 CHECK(mReadMethod != NULL); 45 mGetSizeMethod = env->GetMethodID(mediaDataSourceClass.get(), "getSize", "()J"); 46 CHECK(mGetSizeMethod != NULL); 47 mCloseMethod = env->GetMethodID(mediaDataSourceClass.get(), "close", "()V"); 48 CHECK(mCloseMethod != NULL); 49 50 ScopedLocalRef<jbyteArray> tmp(env, env->NewByteArray(kBufferSize)); 51 mByteArrayObj = (jbyteArray)env->NewGlobalRef(tmp.get()); 52 CHECK(mByteArrayObj != NULL); 53 54 sp<MemoryDealer> memoryDealer = new MemoryDealer(kBufferSize, "JMediaDataSource"); 55 mMemory = memoryDealer->allocate(kBufferSize); 56 if (mMemory == NULL) { 57 ALOGE("Failed to allocate memory!"); 58 } 59} 60 61JMediaDataSource::~JMediaDataSource() { 62 JNIEnv* env = AndroidRuntime::getJNIEnv(); 63 env->DeleteGlobalRef(mMediaDataSourceObj); 64 env->DeleteGlobalRef(mByteArrayObj); 65} 66 67sp<IMemory> JMediaDataSource::getIMemory() { 68 Mutex::Autolock lock(mLock); 69 return mMemory; 70} 71 72ssize_t JMediaDataSource::readAt(off64_t offset, size_t size) { 73 Mutex::Autolock lock(mLock); 74 75 if (mJavaObjStatus != OK || mMemory == NULL) { 76 return -1; 77 } 78 if (size > kBufferSize) { 79 size = kBufferSize; 80 } 81 82 JNIEnv* env = AndroidRuntime::getJNIEnv(); 83 jint numread = env->CallIntMethod(mMediaDataSourceObj, mReadMethod, 84 (jlong)offset, mByteArrayObj, (jint)0, (jint)size); 85 if (env->ExceptionCheck()) { 86 ALOGW("An exception occurred in readAt()"); 87 LOGW_EX(env); 88 env->ExceptionClear(); 89 mJavaObjStatus = UNKNOWN_ERROR; 90 return -1; 91 } 92 if (numread < 0) { 93 if (numread != -1) { 94 ALOGW("An error occurred in readAt()"); 95 mJavaObjStatus = UNKNOWN_ERROR; 96 return -1; 97 } else { 98 // numread == -1 indicates EOF 99 return 0; 100 } 101 } 102 if ((size_t)numread > size) { 103 ALOGE("readAt read too many bytes."); 104 mJavaObjStatus = UNKNOWN_ERROR; 105 return -1; 106 } 107 108 ALOGV("readAt %lld / %zu => %d.", (long long)offset, size, numread); 109 env->GetByteArrayRegion(mByteArrayObj, 0, numread, (jbyte*)mMemory->pointer()); 110 return numread; 111} 112 113status_t JMediaDataSource::getSize(off64_t* size) { 114 Mutex::Autolock lock(mLock); 115 116 if (mJavaObjStatus != OK) { 117 return UNKNOWN_ERROR; 118 } 119 if (mSizeIsCached) { 120 *size = mCachedSize; 121 return OK; 122 } 123 124 JNIEnv* env = AndroidRuntime::getJNIEnv(); 125 *size = env->CallLongMethod(mMediaDataSourceObj, mGetSizeMethod); 126 if (env->ExceptionCheck()) { 127 ALOGW("An exception occurred in getSize()"); 128 LOGW_EX(env); 129 env->ExceptionClear(); 130 // After returning an error, size shouldn't be used by callers. 131 *size = UNKNOWN_ERROR; 132 mJavaObjStatus = UNKNOWN_ERROR; 133 return UNKNOWN_ERROR; 134 } 135 136 // The minimum size should be -1, which indicates unknown size. 137 if (*size < 0) { 138 *size = -1; 139 } 140 141 mCachedSize = *size; 142 mSizeIsCached = true; 143 return OK; 144} 145 146void JMediaDataSource::close() { 147 Mutex::Autolock lock(mLock); 148 149 JNIEnv* env = AndroidRuntime::getJNIEnv(); 150 env->CallVoidMethod(mMediaDataSourceObj, mCloseMethod); 151 // The closed state is effectively the same as an error state. 152 mJavaObjStatus = UNKNOWN_ERROR; 153} 154 155uint32_t JMediaDataSource::getFlags() { 156 return 0; 157} 158 159String8 JMediaDataSource::toString() { 160 return String8::format("JMediaDataSource(pid %d, uid %d)", getpid(), getuid()); 161} 162 163sp<DecryptHandle> JMediaDataSource::DrmInitialization(const char * /* mime */) { 164 return NULL; 165} 166 167} // namespace android 168