10a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia/*
20a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * Copyright 2017, The Android Open Source Project
30a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *
40a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * Licensed under the Apache License, Version 2.0 (the "License");
50a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * you may not use this file except in compliance with the License.
60a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * You may obtain a copy of the License at
70a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *
80a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *     http://www.apache.org/licenses/LICENSE-2.0
90a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia *
100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * Unless required by applicable law or agreed to in writing, software
110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * distributed under the License is distributed on an "AS IS" BASIS,
120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * See the License for the specific language governing permissions and
140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia * limitations under the License.
150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia */
160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia//#define LOG_NDEBUG 0
180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia#define LOG_TAG "JMedia2DataSource-JNI"
190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia#include <utils/Log.h>
200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia#include "android_media_Media2DataSource.h"
220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia#include "android_runtime/AndroidRuntime.h"
240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia#include "android_runtime/Log.h"
250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia#include "jni.h"
260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia#include <nativehelper/JNIHelp.h>
270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia#include <drm/drm_framework_common.h>
290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia#include <media/stagefright/foundation/ADebug.h>
300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia#include <nativehelper/ScopedLocalRef.h>
310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jianamespace android {
330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiastatic const size_t kBufferSize = 64 * 1024;
350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
360a8a8f0b26634395ce64123e2a385670d6b07c00Wei JiaJMedia2DataSource::JMedia2DataSource(JNIEnv* env, jobject source)
370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    : mJavaObjStatus(OK),
380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia      mSizeIsCached(false),
390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia      mCachedSize(0) {
400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    mMedia2DataSourceObj = env->NewGlobalRef(source);
410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    CHECK(mMedia2DataSourceObj != NULL);
420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    ScopedLocalRef<jclass> media2DataSourceClass(env, env->GetObjectClass(mMedia2DataSourceObj));
440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    CHECK(media2DataSourceClass.get() != NULL);
450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    mReadAtMethod = env->GetMethodID(media2DataSourceClass.get(), "readAt", "(J[BII)I");
470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    CHECK(mReadAtMethod != NULL);
480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    mGetSizeMethod = env->GetMethodID(media2DataSourceClass.get(), "getSize", "()J");
490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    CHECK(mGetSizeMethod != NULL);
500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    mCloseMethod = env->GetMethodID(media2DataSourceClass.get(), "close", "()V");
510a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    CHECK(mCloseMethod != NULL);
520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    ScopedLocalRef<jbyteArray> tmp(env, env->NewByteArray(kBufferSize));
540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    mByteArrayObj = (jbyteArray)env->NewGlobalRef(tmp.get());
550a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    CHECK(mByteArrayObj != NULL);
560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia}
570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
580a8a8f0b26634395ce64123e2a385670d6b07c00Wei JiaJMedia2DataSource::~JMedia2DataSource() {
590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    JNIEnv* env = AndroidRuntime::getJNIEnv();
600a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    env->DeleteGlobalRef(mMedia2DataSourceObj);
610a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    env->DeleteGlobalRef(mByteArrayObj);
620a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia}
630a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
640a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiastatus_t JMedia2DataSource::initCheck() const {
650a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    return OK;
660a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia}
670a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
680a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiassize_t JMedia2DataSource::readAt(off64_t offset, void *data, size_t size) {
690a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    Mutex::Autolock lock(mLock);
700a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
710a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    if (mJavaObjStatus != OK) {
720a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return -1;
730a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
740a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    if (size > kBufferSize) {
750a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        size = kBufferSize;
760a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
770a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
780a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    JNIEnv* env = AndroidRuntime::getJNIEnv();
790a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    jint numread = env->CallIntMethod(mMedia2DataSourceObj, mReadAtMethod,
800a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            (jlong)offset, mByteArrayObj, (jint)0, (jint)size);
810a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    if (env->ExceptionCheck()) {
820a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        ALOGW("An exception occurred in readAt()");
830a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        LOGW_EX(env);
840a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        env->ExceptionClear();
850a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mJavaObjStatus = UNKNOWN_ERROR;
860a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return -1;
870a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
880a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    if (numread < 0) {
890a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        if (numread != -1) {
900a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            ALOGW("An error occurred in readAt()");
910a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            mJavaObjStatus = UNKNOWN_ERROR;
920a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return -1;
930a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        } else {
940a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            // numread == -1 indicates EOF
950a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia            return 0;
960a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        }
970a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
980a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    if ((size_t)numread > size) {
990a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        ALOGE("readAt read too many bytes.");
1000a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mJavaObjStatus = UNKNOWN_ERROR;
1010a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return -1;
1020a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
1030a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1040a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    ALOGV("readAt %lld / %zu => %d.", (long long)offset, size, numread);
1050a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    env->GetByteArrayRegion(mByteArrayObj, 0, numread, (jbyte*)data);
1060a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    return numread;
1070a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia}
1080a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1090a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiastatus_t JMedia2DataSource::getSize(off64_t* size) {
1100a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    Mutex::Autolock lock(mLock);
1110a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1120a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    if (mJavaObjStatus != OK) {
1130a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return UNKNOWN_ERROR;
1140a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
1150a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    if (mSizeIsCached) {
1160a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        *size = mCachedSize;
1170a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return OK;
1180a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
1190a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1200a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    JNIEnv* env = AndroidRuntime::getJNIEnv();
1210a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    *size = env->CallLongMethod(mMedia2DataSourceObj, mGetSizeMethod);
1220a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    if (env->ExceptionCheck()) {
1230a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        ALOGW("An exception occurred in getSize()");
1240a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        LOGW_EX(env);
1250a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        env->ExceptionClear();
1260a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        // After returning an error, size shouldn't be used by callers.
1270a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        *size = UNKNOWN_ERROR;
1280a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        mJavaObjStatus = UNKNOWN_ERROR;
1290a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        return UNKNOWN_ERROR;
1300a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
1310a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1320a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // The minimum size should be -1, which indicates unknown size.
1330a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    if (*size < 0) {
1340a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia        *size = -1;
1350a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    }
1360a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1370a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    mCachedSize = *size;
1380a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    mSizeIsCached = true;
1390a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    return OK;
1400a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia}
1410a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1420a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jiavoid JMedia2DataSource::close() {
1430a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    Mutex::Autolock lock(mLock);
1440a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1450a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    JNIEnv* env = AndroidRuntime::getJNIEnv();
1460a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    env->CallVoidMethod(mMedia2DataSourceObj, mCloseMethod);
1470a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    // The closed state is effectively the same as an error state.
1480a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    mJavaObjStatus = UNKNOWN_ERROR;
1490a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia}
1500a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1510a8a8f0b26634395ce64123e2a385670d6b07c00Wei JiaString8 JMedia2DataSource::toString() {
1520a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    return String8::format("JMedia2DataSource(pid %d, uid %d)", getpid(), getuid());
1530a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia}
1540a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1550a8a8f0b26634395ce64123e2a385670d6b07c00Wei JiaString8 JMedia2DataSource::getMIMEType() const {
1560a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia    return String8("application/octet-stream");
1570a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia}
1580a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia
1590a8a8f0b26634395ce64123e2a385670d6b07c00Wei Jia}  // namespace android
160