• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <nativehelper/JNIHelp.h>
27 
28 #include <binder/MemoryDealer.h>
29 #include <media/stagefright/foundation/ADebug.h>
30 #include <nativehelper/ScopedLocalRef.h>
31 
32 namespace android {
33 
JMediaDataSource(JNIEnv * env,jobject source)34 JMediaDataSource::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 
~JMediaDataSource()60 JMediaDataSource::~JMediaDataSource() {
61     JNIEnv* env = AndroidRuntime::getJNIEnv();
62     env->DeleteGlobalRef(mMediaDataSourceObj);
63     env->DeleteGlobalRef(mByteArrayObj);
64 }
65 
getIMemory()66 sp<IMemory> JMediaDataSource::getIMemory() {
67     Mutex::Autolock lock(mLock);
68     return mMemory;
69 }
70 
readAt(off64_t offset,size_t size)71 ssize_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,
109         (jbyte*)mMemory->unsecurePointer());
110     return numread;
111 }
112 
getSize(off64_t * size)113 status_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 
close()146 void 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 
getFlags()155 uint32_t JMediaDataSource::getFlags() {
156     return 0;
157 }
158 
toString()159 String8 JMediaDataSource::toString() {
160     return String8::format("JMediaDataSource(pid %d, uid %d)", getpid(), getuid());
161 }
162 
163 }  // namespace android
164