android_media_MediaDataSource.cpp revision 73c74698d094e57af60d55afc790a72a966ae263
14eaa2938084353a54dc259466172909329a048ccChris Watkins/*
24eaa2938084353a54dc259466172909329a048ccChris Watkins * Copyright 2015, The Android Open Source Project
34eaa2938084353a54dc259466172909329a048ccChris Watkins *
44eaa2938084353a54dc259466172909329a048ccChris Watkins * Licensed under the Apache License, Version 2.0 (the "License");
54eaa2938084353a54dc259466172909329a048ccChris Watkins * you may not use this file except in compliance with the License.
64eaa2938084353a54dc259466172909329a048ccChris Watkins * You may obtain a copy of the License at
74eaa2938084353a54dc259466172909329a048ccChris Watkins *
84eaa2938084353a54dc259466172909329a048ccChris Watkins *     http://www.apache.org/licenses/LICENSE-2.0
94eaa2938084353a54dc259466172909329a048ccChris Watkins *
104eaa2938084353a54dc259466172909329a048ccChris Watkins * Unless required by applicable law or agreed to in writing, software
114eaa2938084353a54dc259466172909329a048ccChris Watkins * distributed under the License is distributed on an "AS IS" BASIS,
124eaa2938084353a54dc259466172909329a048ccChris Watkins * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134eaa2938084353a54dc259466172909329a048ccChris Watkins * See the License for the specific language governing permissions and
144eaa2938084353a54dc259466172909329a048ccChris Watkins * limitations under the License.
154eaa2938084353a54dc259466172909329a048ccChris Watkins */
164eaa2938084353a54dc259466172909329a048ccChris Watkins
174eaa2938084353a54dc259466172909329a048ccChris Watkins//#define LOG_NDEBUG 0
184eaa2938084353a54dc259466172909329a048ccChris Watkins#define LOG_TAG "JMediaDataSource-JNI"
194eaa2938084353a54dc259466172909329a048ccChris Watkins#include <utils/Log.h>
204eaa2938084353a54dc259466172909329a048ccChris Watkins
214eaa2938084353a54dc259466172909329a048ccChris Watkins#include "android_media_MediaDataSource.h"
224eaa2938084353a54dc259466172909329a048ccChris Watkins
234eaa2938084353a54dc259466172909329a048ccChris Watkins#include "android_runtime/AndroidRuntime.h"
244eaa2938084353a54dc259466172909329a048ccChris Watkins#include "android_runtime/Log.h"
254eaa2938084353a54dc259466172909329a048ccChris Watkins#include "jni.h"
264eaa2938084353a54dc259466172909329a048ccChris Watkins#include "JNIHelp.h"
274eaa2938084353a54dc259466172909329a048ccChris Watkins
284eaa2938084353a54dc259466172909329a048ccChris Watkins#include <binder/MemoryDealer.h>
294eaa2938084353a54dc259466172909329a048ccChris Watkins#include <media/stagefright/foundation/ADebug.h>
304eaa2938084353a54dc259466172909329a048ccChris Watkins#include <nativehelper/ScopedLocalRef.h>
314eaa2938084353a54dc259466172909329a048ccChris Watkins
324eaa2938084353a54dc259466172909329a048ccChris Watkinsnamespace android {
334eaa2938084353a54dc259466172909329a048ccChris Watkins
344eaa2938084353a54dc259466172909329a048ccChris WatkinsJMediaDataSource::JMediaDataSource(JNIEnv* env, jobject source)
354eaa2938084353a54dc259466172909329a048ccChris Watkins    : mJavaObjStatus(OK), mSizeIsCached(false), mCachedSize(0), mMemory(NULL) {
364eaa2938084353a54dc259466172909329a048ccChris Watkins    mMediaDataSourceObj = env->NewGlobalRef(source);
374eaa2938084353a54dc259466172909329a048ccChris Watkins    CHECK(mMediaDataSourceObj != NULL);
384eaa2938084353a54dc259466172909329a048ccChris Watkins
394eaa2938084353a54dc259466172909329a048ccChris Watkins    ScopedLocalRef<jclass> mediaDataSourceClass(env, env->GetObjectClass(mMediaDataSourceObj));
404eaa2938084353a54dc259466172909329a048ccChris Watkins    CHECK(mediaDataSourceClass.get() != NULL);
414eaa2938084353a54dc259466172909329a048ccChris Watkins
42bc10185fa1669a151568feb72277785d323fc344Chong Zhang    mReadMethod = env->GetMethodID(mediaDataSourceClass.get(), "readAt", "(J[BII)I");
434eaa2938084353a54dc259466172909329a048ccChris Watkins    CHECK(mReadMethod != NULL);
444eaa2938084353a54dc259466172909329a048ccChris Watkins    mGetSizeMethod = env->GetMethodID(mediaDataSourceClass.get(), "getSize", "()J");
454eaa2938084353a54dc259466172909329a048ccChris Watkins    CHECK(mGetSizeMethod != NULL);
464eaa2938084353a54dc259466172909329a048ccChris Watkins    mCloseMethod = env->GetMethodID(mediaDataSourceClass.get(), "close", "()V");
474eaa2938084353a54dc259466172909329a048ccChris Watkins    CHECK(mCloseMethod != NULL);
484eaa2938084353a54dc259466172909329a048ccChris Watkins
494eaa2938084353a54dc259466172909329a048ccChris Watkins    ScopedLocalRef<jbyteArray> tmp(env, env->NewByteArray(kBufferSize));
504eaa2938084353a54dc259466172909329a048ccChris Watkins    mByteArrayObj = (jbyteArray)env->NewGlobalRef(tmp.get());
514eaa2938084353a54dc259466172909329a048ccChris Watkins    CHECK(mByteArrayObj != NULL);
524eaa2938084353a54dc259466172909329a048ccChris Watkins
534eaa2938084353a54dc259466172909329a048ccChris Watkins    sp<MemoryDealer> memoryDealer = new MemoryDealer(kBufferSize, "JMediaDataSource");
544eaa2938084353a54dc259466172909329a048ccChris Watkins    mMemory = memoryDealer->allocate(kBufferSize);
554eaa2938084353a54dc259466172909329a048ccChris Watkins    if (mMemory == NULL) {
564eaa2938084353a54dc259466172909329a048ccChris Watkins        ALOGE("Failed to allocate memory!");
574eaa2938084353a54dc259466172909329a048ccChris Watkins    }
584eaa2938084353a54dc259466172909329a048ccChris Watkins}
594eaa2938084353a54dc259466172909329a048ccChris Watkins
604eaa2938084353a54dc259466172909329a048ccChris WatkinsJMediaDataSource::~JMediaDataSource() {
614eaa2938084353a54dc259466172909329a048ccChris Watkins    JNIEnv* env = AndroidRuntime::getJNIEnv();
624eaa2938084353a54dc259466172909329a048ccChris Watkins    env->DeleteGlobalRef(mMediaDataSourceObj);
634eaa2938084353a54dc259466172909329a048ccChris Watkins    env->DeleteGlobalRef(mByteArrayObj);
644eaa2938084353a54dc259466172909329a048ccChris Watkins}
654eaa2938084353a54dc259466172909329a048ccChris Watkins
664eaa2938084353a54dc259466172909329a048ccChris Watkinssp<IMemory> JMediaDataSource::getIMemory() {
674eaa2938084353a54dc259466172909329a048ccChris Watkins    Mutex::Autolock lock(mLock);
684eaa2938084353a54dc259466172909329a048ccChris Watkins    return mMemory;
694eaa2938084353a54dc259466172909329a048ccChris Watkins}
704eaa2938084353a54dc259466172909329a048ccChris Watkins
714eaa2938084353a54dc259466172909329a048ccChris Watkinsssize_t JMediaDataSource::readAt(off64_t offset, size_t size) {
724eaa2938084353a54dc259466172909329a048ccChris Watkins    Mutex::Autolock lock(mLock);
734eaa2938084353a54dc259466172909329a048ccChris Watkins
744eaa2938084353a54dc259466172909329a048ccChris Watkins    if (mJavaObjStatus != OK || mMemory == NULL) {
754eaa2938084353a54dc259466172909329a048ccChris Watkins        return -1;
764eaa2938084353a54dc259466172909329a048ccChris Watkins    }
774eaa2938084353a54dc259466172909329a048ccChris Watkins    if (size > kBufferSize) {
784eaa2938084353a54dc259466172909329a048ccChris Watkins        size = kBufferSize;
794eaa2938084353a54dc259466172909329a048ccChris Watkins    }
804eaa2938084353a54dc259466172909329a048ccChris Watkins
814eaa2938084353a54dc259466172909329a048ccChris Watkins    JNIEnv* env = AndroidRuntime::getJNIEnv();
824eaa2938084353a54dc259466172909329a048ccChris Watkins    jint numread = env->CallIntMethod(mMediaDataSourceObj, mReadMethod,
83bc10185fa1669a151568feb72277785d323fc344Chong Zhang            (jlong)offset, mByteArrayObj, (jint)0, (jint)size);
844eaa2938084353a54dc259466172909329a048ccChris Watkins    if (env->ExceptionCheck()) {
854eaa2938084353a54dc259466172909329a048ccChris Watkins        ALOGW("An exception occurred in readAt()");
864eaa2938084353a54dc259466172909329a048ccChris Watkins        LOGW_EX(env);
874eaa2938084353a54dc259466172909329a048ccChris Watkins        env->ExceptionClear();
884eaa2938084353a54dc259466172909329a048ccChris Watkins        mJavaObjStatus = UNKNOWN_ERROR;
894eaa2938084353a54dc259466172909329a048ccChris Watkins        return -1;
904eaa2938084353a54dc259466172909329a048ccChris Watkins    }
914eaa2938084353a54dc259466172909329a048ccChris Watkins    if (numread < 0) {
92bc10185fa1669a151568feb72277785d323fc344Chong Zhang        if (numread != -1) {
93bc10185fa1669a151568feb72277785d323fc344Chong Zhang            ALOGW("An error occurred in readAt()");
94bc10185fa1669a151568feb72277785d323fc344Chong Zhang            mJavaObjStatus = UNKNOWN_ERROR;
95bc10185fa1669a151568feb72277785d323fc344Chong Zhang            return -1;
96bc10185fa1669a151568feb72277785d323fc344Chong Zhang        } else {
97bc10185fa1669a151568feb72277785d323fc344Chong Zhang            // numread == -1 indicates EOF
98bc10185fa1669a151568feb72277785d323fc344Chong Zhang            return 0;
99bc10185fa1669a151568feb72277785d323fc344Chong Zhang        }
1004eaa2938084353a54dc259466172909329a048ccChris Watkins    }
1014eaa2938084353a54dc259466172909329a048ccChris Watkins    if ((size_t)numread > size) {
1024eaa2938084353a54dc259466172909329a048ccChris Watkins        ALOGE("readAt read too many bytes.");
1034eaa2938084353a54dc259466172909329a048ccChris Watkins        mJavaObjStatus = UNKNOWN_ERROR;
1044eaa2938084353a54dc259466172909329a048ccChris Watkins        return -1;
1054eaa2938084353a54dc259466172909329a048ccChris Watkins    }
1064eaa2938084353a54dc259466172909329a048ccChris Watkins
1074eaa2938084353a54dc259466172909329a048ccChris Watkins    ALOGV("readAt %lld / %zu => %d.", (long long)offset, size, numread);
1084eaa2938084353a54dc259466172909329a048ccChris Watkins    env->GetByteArrayRegion(mByteArrayObj, 0, numread, (jbyte*)mMemory->pointer());
1094eaa2938084353a54dc259466172909329a048ccChris Watkins    return numread;
1104eaa2938084353a54dc259466172909329a048ccChris Watkins}
1114eaa2938084353a54dc259466172909329a048ccChris Watkins
1124eaa2938084353a54dc259466172909329a048ccChris Watkinsstatus_t JMediaDataSource::getSize(off64_t* size) {
1134eaa2938084353a54dc259466172909329a048ccChris Watkins    Mutex::Autolock lock(mLock);
1144eaa2938084353a54dc259466172909329a048ccChris Watkins
1154eaa2938084353a54dc259466172909329a048ccChris Watkins    if (mJavaObjStatus != OK) {
1164eaa2938084353a54dc259466172909329a048ccChris Watkins        return UNKNOWN_ERROR;
1174eaa2938084353a54dc259466172909329a048ccChris Watkins    }
1184eaa2938084353a54dc259466172909329a048ccChris Watkins    if (mSizeIsCached) {
1197c7fef1585b7ec36d181b0f797f2713cb2dde291Lajos Molnar        *size = mCachedSize;
1207c7fef1585b7ec36d181b0f797f2713cb2dde291Lajos Molnar        return OK;
1214eaa2938084353a54dc259466172909329a048ccChris Watkins    }
1224eaa2938084353a54dc259466172909329a048ccChris Watkins
1234eaa2938084353a54dc259466172909329a048ccChris Watkins    JNIEnv* env = AndroidRuntime::getJNIEnv();
1244eaa2938084353a54dc259466172909329a048ccChris Watkins    *size = env->CallLongMethod(mMediaDataSourceObj, mGetSizeMethod);
1254eaa2938084353a54dc259466172909329a048ccChris Watkins    if (env->ExceptionCheck()) {
1264eaa2938084353a54dc259466172909329a048ccChris Watkins        ALOGW("An exception occurred in getSize()");
1274eaa2938084353a54dc259466172909329a048ccChris Watkins        LOGW_EX(env);
1284eaa2938084353a54dc259466172909329a048ccChris Watkins        env->ExceptionClear();
1294eaa2938084353a54dc259466172909329a048ccChris Watkins        // After returning an error, size shouldn't be used by callers.
1304eaa2938084353a54dc259466172909329a048ccChris Watkins        *size = UNKNOWN_ERROR;
1314eaa2938084353a54dc259466172909329a048ccChris Watkins        mJavaObjStatus = UNKNOWN_ERROR;
1324eaa2938084353a54dc259466172909329a048ccChris Watkins        return UNKNOWN_ERROR;
1334eaa2938084353a54dc259466172909329a048ccChris Watkins    }
1344eaa2938084353a54dc259466172909329a048ccChris Watkins
1354eaa2938084353a54dc259466172909329a048ccChris Watkins    // The minimum size should be -1, which indicates unknown size.
1364eaa2938084353a54dc259466172909329a048ccChris Watkins    if (*size < 0) {
1374eaa2938084353a54dc259466172909329a048ccChris Watkins        *size = -1;
1384eaa2938084353a54dc259466172909329a048ccChris Watkins    }
1394eaa2938084353a54dc259466172909329a048ccChris Watkins
1404eaa2938084353a54dc259466172909329a048ccChris Watkins    mCachedSize = *size;
1414eaa2938084353a54dc259466172909329a048ccChris Watkins    mSizeIsCached = true;
1424eaa2938084353a54dc259466172909329a048ccChris Watkins    return OK;
1434eaa2938084353a54dc259466172909329a048ccChris Watkins}
1444eaa2938084353a54dc259466172909329a048ccChris Watkins
1454eaa2938084353a54dc259466172909329a048ccChris Watkinsvoid JMediaDataSource::close() {
1464eaa2938084353a54dc259466172909329a048ccChris Watkins    Mutex::Autolock lock(mLock);
1474eaa2938084353a54dc259466172909329a048ccChris Watkins
1484eaa2938084353a54dc259466172909329a048ccChris Watkins    JNIEnv* env = AndroidRuntime::getJNIEnv();
1494eaa2938084353a54dc259466172909329a048ccChris Watkins    env->CallVoidMethod(mMediaDataSourceObj, mCloseMethod);
1504eaa2938084353a54dc259466172909329a048ccChris Watkins    // The closed state is effectively the same as an error state.
1514eaa2938084353a54dc259466172909329a048ccChris Watkins    mJavaObjStatus = UNKNOWN_ERROR;
1524eaa2938084353a54dc259466172909329a048ccChris Watkins}
1534eaa2938084353a54dc259466172909329a048ccChris Watkins
154fbc164ba3c2105265b031503bdfebdbcd7256fbeWei Jiauint32_t JMediaDataSource::getFlags() {
155fbc164ba3c2105265b031503bdfebdbcd7256fbeWei Jia    return 0;
156fbc164ba3c2105265b031503bdfebdbcd7256fbeWei Jia}
157fbc164ba3c2105265b031503bdfebdbcd7256fbeWei Jia
15873c74698d094e57af60d55afc790a72a966ae263Marco NelissenString8 JMediaDataSource::toString() {
15973c74698d094e57af60d55afc790a72a966ae263Marco Nelissen    return String8::format("JMediaDataSource(pid %d, uid %d)", getpid(), getuid());
16073c74698d094e57af60d55afc790a72a966ae263Marco Nelissen}
16173c74698d094e57af60d55afc790a72a966ae263Marco Nelissen
1624eaa2938084353a54dc259466172909329a048ccChris Watkins}  // namespace android
163