Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4ff8d379 authored by Marco Nelissen's avatar Marco Nelissen Committed by Android (Google) Code Review
Browse files

Merge "Let apps provide a custom data source for extractors" into jb-mr1-dev

parents e0d5ceef c209a06c
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package android.media;

import java.io.Closeable;

/**
 * An abstraction for a media data source, e.g. a file or an http stream
 * {@hide}
 */
public interface DataSource extends Closeable {
    /**
     * Reads data from the data source at the requested position
     *
     * @param offset where in the source to read
     * @param buffer the buffer to read the data into
     * @param size how many bytes to read
     * @return the number of bytes read, or -1 if there was an error
     */
    public int readAt(long offset, byte[] buffer, int size);

    /**
     * Gets the size of the data source.
     *
     * @return size of data source, or -1 if the length is unknown
     */
    public long getSize();
}
+7 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.content.res.AssetFileDescriptor;
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.net.Uri;

import java.io.FileDescriptor;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -59,6 +60,12 @@ final public class MediaExtractor {
        native_setup();
    }

    /**
     * Sets the DataSource object to be used as the data source for this extractor
     * {@hide}
     */
    public native final void setDataSource(DataSource source);

    /**
     * Sets the data source as a content Uri.
     *
+100 −0
Original line number Diff line number Diff line
@@ -44,6 +44,72 @@ struct fields_t {

static fields_t gFields;

class JavaDataSourceBridge : public DataSource {
    jmethodID mReadMethod;
    jmethodID mGetSizeMethod;
    jmethodID mCloseMethod;
    jobject   mDataSource;
 public:
    JavaDataSourceBridge(JNIEnv *env, jobject source) {
        mDataSource = env->NewGlobalRef(source);

        jclass datasourceclass = env->GetObjectClass(mDataSource);
        CHECK(datasourceclass != NULL);

        mReadMethod = env->GetMethodID(datasourceclass, "readAt", "(J[BI)I");
        CHECK(mReadMethod != NULL);

        mGetSizeMethod = env->GetMethodID(datasourceclass, "getSize", "()J");
        CHECK(mGetSizeMethod != NULL);

        mCloseMethod = env->GetMethodID(datasourceclass, "close", "()V");
        CHECK(mCloseMethod != NULL);
    }

    ~JavaDataSourceBridge() {
        JNIEnv *env = AndroidRuntime::getJNIEnv();
        env->CallVoidMethod(mDataSource, mCloseMethod);
        env->DeleteGlobalRef(mDataSource);
    }

    virtual status_t initCheck() const {
        return OK;
    }

    virtual ssize_t readAt(off64_t offset, void* buffer, size_t size) {
        JNIEnv *env = AndroidRuntime::getJNIEnv();

        // XXX could optimize this by reusing the same array
        jbyteArray byteArrayObj = env->NewByteArray(size);
        env->DeleteLocalRef(env->GetObjectClass(mDataSource));
        env->DeleteLocalRef(env->GetObjectClass(byteArrayObj));
        ssize_t numread = env->CallIntMethod(mDataSource, mReadMethod, offset, byteArrayObj, size);
        env->GetByteArrayRegion(byteArrayObj, 0, size, (jbyte*) buffer);
        env->DeleteLocalRef(byteArrayObj);
        if (env->ExceptionCheck()) {
            ALOGW("Exception occurred while reading %d at %lld", size, offset);
            LOGW_EX(env);
            env->ExceptionClear();
            return -1;
        }
        return numread;
    }

    virtual status_t getSize(off64_t *size) {
        JNIEnv *env = AndroidRuntime::getJNIEnv();

        CHECK(size != NULL);

        int64_t len = env->CallLongMethod(mDataSource, mGetSizeMethod);
        if (len < 0) {
            *size = ERROR_UNSUPPORTED;
        } else {
            *size = len;
        }
        return OK;
    }
};

////////////////////////////////////////////////////////////////////////////////

JMediaExtractor::JMediaExtractor(JNIEnv *env, jobject thiz)
@@ -76,6 +142,10 @@ status_t JMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) {
    return mImpl->setDataSource(fd, offset, size);
}

status_t JMediaExtractor::setDataSource(const sp<DataSource> &datasource) {
    return mImpl->setDataSource(datasource);
}

size_t JMediaExtractor::countTracks() const {
    return mImpl->countTracks();
}
@@ -625,6 +695,33 @@ static void android_media_MediaExtractor_setDataSourceFd(
    }
}

static void android_media_MediaExtractor_setDataSourceCallback(
        JNIEnv *env, jobject thiz,
        jobject callbackObj) {
    sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);

    if (extractor == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException", NULL);
        return;
    }

    if (callbackObj == NULL) {
        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
        return;
    }

    sp<JavaDataSourceBridge> bridge = new JavaDataSourceBridge(env, callbackObj);
    status_t err = extractor->setDataSource(bridge);

    if (err != OK) {
        jniThrowException(
                env,
                "java/io/IOException",
                "Failed to instantiate extractor.");
        return;
    }
}

static jlong android_media_MediaExtractor_getCachedDurationUs(
        JNIEnv *env, jobject thiz) {
    sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
@@ -713,6 +810,9 @@ static JNINativeMethod gMethods[] = {
    { "setDataSource", "(Ljava/io/FileDescriptor;JJ)V",
      (void *)android_media_MediaExtractor_setDataSourceFd },

    { "setDataSource", "(Landroid/media/DataSource;)V",
      (void *)android_media_MediaExtractor_setDataSourceCallback },

    { "getCachedDuration", "()J",
      (void *)android_media_MediaExtractor_getCachedDurationUs },

+2 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@

#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/DataSource.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
@@ -39,6 +40,7 @@ struct JMediaExtractor : public RefBase {
            const KeyedVector<String8, String8> *headers);

    status_t setDataSource(int fd, off64_t offset, off64_t size);
    status_t setDataSource(const sp<DataSource> &source);

    size_t countTracks() const;
    status_t getTrackFormat(size_t index, jobject *format) const;