android_media_MediaDataSource.cpp revision fbc164ba3c2105265b031503bdfebdbcd7256fbe
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 <media/stagefright/foundation/ADebug.h> 30#include <nativehelper/ScopedLocalRef.h> 31 32namespace android { 33 34JMediaDataSource::JMediaDataSource(JNIEnv* env, jobject source) 35 : mJavaObjStatus(OK), mSizeIsCached(false), mCachedSize(0), mMemory(NULL) { 36 mMediaDataSourceObj = env->NewGlobalRef(source); 37 CHECK(mMediaDataSourceObj != NULL); 38 39 ScopedLocalRef<jclass> mediaDataSourceClass(env, env->GetObjectClass(mMediaDataSourceObj)); 40 CHECK(mediaDataSourceClass.get() != NULL); 41 42 mReadMethod = env->GetMethodID(mediaDataSourceClass.get(), "readAt", "(J[BII)I"); 43 CHECK(mReadMethod != NULL); 44 mGetSizeMethod = env->GetMethodID(mediaDataSourceClass.get(), "getSize", "()J"); 45 CHECK(mGetSizeMethod != NULL); 46 mCloseMethod = env->GetMethodID(mediaDataSourceClass.get(), "close", "()V"); 47 CHECK(mCloseMethod != NULL); 48 49 ScopedLocalRef<jbyteArray> tmp(env, env->NewByteArray(kBufferSize)); 50 mByteArrayObj = (jbyteArray)env->NewGlobalRef(tmp.get()); 51 CHECK(mByteArrayObj != NULL); 52 53 sp<MemoryDealer> memoryDealer = new MemoryDealer(kBufferSize, "JMediaDataSource"); 54 mMemory = memoryDealer->allocate(kBufferSize); 55 if (mMemory == NULL) { 56 ALOGE("Failed to allocate memory!"); 57 } 58} 59 60JMediaDataSource::~JMediaDataSource() { 61 JNIEnv* env = AndroidRuntime::getJNIEnv(); 62 env->DeleteGlobalRef(mMediaDataSourceObj); 63 env->DeleteGlobalRef(mByteArrayObj); 64} 65 66sp<IMemory> JMediaDataSource::getIMemory() { 67 Mutex::Autolock lock(mLock); 68 return mMemory; 69} 70 71ssize_t JMediaDataSource::readAt(off64_t offset, size_t size) { 72 Mutex::Autolock lock(mLock); 73 74 if (mJavaObjStatus != OK || mMemory == NULL) { 75 return -1; 76 } 77 if (size > kBufferSize) { 78 size = kBufferSize; 79 } 80 81 JNIEnv* env = AndroidRuntime::getJNIEnv(); 82 jint numread = env->CallIntMethod(mMediaDataSourceObj, mReadMethod, 83 (jlong)offset, mByteArrayObj, (jint)0, (jint)size); 84 if (env->ExceptionCheck()) { 85 ALOGW("An exception occurred in readAt()"); 86 LOGW_EX(env); 87 env->ExceptionClear(); 88 mJavaObjStatus = UNKNOWN_ERROR; 89 return -1; 90 } 91 if (numread < 0) { 92 if (numread != -1) { 93 ALOGW("An error occurred in readAt()"); 94 mJavaObjStatus = UNKNOWN_ERROR; 95 return -1; 96 } else { 97 // numread == -1 indicates EOF 98 return 0; 99 } 100 } 101 if ((size_t)numread > size) { 102 ALOGE("readAt read too many bytes."); 103 mJavaObjStatus = UNKNOWN_ERROR; 104 return -1; 105 } 106 107 ALOGV("readAt %lld / %zu => %d.", (long long)offset, size, numread); 108 env->GetByteArrayRegion(mByteArrayObj, 0, numread, (jbyte*)mMemory->pointer()); 109 return numread; 110} 111 112status_t JMediaDataSource::getSize(off64_t* size) { 113 Mutex::Autolock lock(mLock); 114 115 if (mJavaObjStatus != OK) { 116 return UNKNOWN_ERROR; 117 } 118 if (mSizeIsCached) { 119 return mCachedSize; 120 } 121 122 JNIEnv* env = AndroidRuntime::getJNIEnv(); 123 *size = env->CallLongMethod(mMediaDataSourceObj, mGetSizeMethod); 124 if (env->ExceptionCheck()) { 125 ALOGW("An exception occurred in getSize()"); 126 LOGW_EX(env); 127 env->ExceptionClear(); 128 // After returning an error, size shouldn't be used by callers. 129 *size = UNKNOWN_ERROR; 130 mJavaObjStatus = UNKNOWN_ERROR; 131 return UNKNOWN_ERROR; 132 } 133 134 // The minimum size should be -1, which indicates unknown size. 135 if (*size < 0) { 136 *size = -1; 137 } 138 139 mCachedSize = *size; 140 mSizeIsCached = true; 141 return OK; 142} 143 144void JMediaDataSource::close() { 145 Mutex::Autolock lock(mLock); 146 147 JNIEnv* env = AndroidRuntime::getJNIEnv(); 148 env->CallVoidMethod(mMediaDataSourceObj, mCloseMethod); 149 // The closed state is effectively the same as an error state. 150 mJavaObjStatus = UNKNOWN_ERROR; 151} 152 153uint32_t JMediaDataSource::getFlags() { 154 return 0; 155} 156 157} // namespace android 158