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

Commit aba67139 authored by Andreas Huber's avatar Andreas Huber
Browse files

API that allows usage of MediaCodec APIs without polling.

Change-Id: Iebccdd3aec74a2cfa9ad0bf16c0c6006a3b72999
related-to-bug: 11990118
parent 7023df08
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -12845,6 +12845,7 @@ package android.media {
    method public final void queueSecureInputBuffer(int, int, android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException;
    method public final void release();
    method public final void releaseOutputBuffer(int, boolean);
    method public void setNotificationCallback(android.media.MediaCodec.NotificationCallback);
    method public final void setParameters(android.os.Bundle);
    method public final void setVideoScalingMode(int);
    method public final void signalEndOfInputStream();
@@ -12894,6 +12895,10 @@ package android.media {
    field public int numSubSamples;
  }
  public static abstract interface MediaCodec.NotificationCallback {
    method public abstract void onCodecNotify(android.media.MediaCodec);
  }
  public final class MediaCodecInfo {
    method public final android.media.MediaCodecInfo.CodecCapabilities getCapabilitiesForType(java.lang.String);
    method public final java.lang.String getName();
@@ -52412,7 +52417,7 @@ package org.json {
    method public java.lang.String getString(java.lang.String) throws org.json.JSONException;
    method public boolean has(java.lang.String);
    method public boolean isNull(java.lang.String);
    method public java.util.Iterator keys();
    method public java.util.Iterator<java.lang.String> keys();
    method public int length();
    method public org.json.JSONArray names();
    method public static java.lang.String numberToString(java.lang.Number) throws org.json.JSONException;
+64 −1
Original line number Diff line number Diff line
@@ -21,6 +21,9 @@ import android.media.MediaCodecList;
import android.media.MediaCrypto;
import android.media.MediaFormat;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.Surface;

import java.io.IOException;
@@ -173,6 +176,33 @@ final public class MediaCodec {
     */
    public static final int BUFFER_FLAG_END_OF_STREAM         = 4;

    private EventHandler mEventHandler;
    private NotificationCallback mNotificationCallback;

    static final int EVENT_NOTIFY = 1;

    private class EventHandler extends Handler {
        private MediaCodec mCodec;

        public EventHandler(MediaCodec codec, Looper looper) {
            super(looper);
            mCodec = codec;
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case EVENT_NOTIFY:
                {
                    if (mNotificationCallback != null) {
                        mNotificationCallback.onCodecNotify(mCodec);
                    }
                    break;
                }
            }
        }
    }

    /**
     * Instantiate a decoder supporting input data of the given mime type.
     *
@@ -228,6 +258,15 @@ final public class MediaCodec {

    private MediaCodec(
            String name, boolean nameIsType, boolean encoder) {
        Looper looper;
        if ((looper = Looper.myLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else if ((looper = Looper.getMainLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else {
            mEventHandler = null;
        }

        native_setup(name, nameIsType, encoder);
    }

@@ -308,7 +347,15 @@ final public class MediaCodec {
     * To ensure that it is available to other client call {@link #release}
     * and don't just rely on garbage collection to eventually do this for you.
     */
    public native final void stop();
    public final void stop() {
        native_stop();

        if (mEventHandler != null) {
            mEventHandler.removeMessages(EVENT_NOTIFY);
        }
    }

    private native final void native_stop();

    /**
     * Flush both input and output ports of the component, all indices
@@ -639,6 +686,22 @@ final public class MediaCodec {
        setParameters(keys, values);
    }

    public void setNotificationCallback(NotificationCallback cb) {
        mNotificationCallback = cb;
    }

    public interface NotificationCallback {
        void onCodecNotify(MediaCodec codec);
    }

    private void postEventFromNative(
            int what, int arg1, int arg2, Object obj) {
        if (mEventHandler != null) {
            Message msg = mEventHandler.obtainMessage(what, arg1, arg2, obj);
            mEventHandler.sendMessage(msg);
        }
    }

    private native final void setParameters(String[] keys, Object[] values);

    /**
+117 −10
Original line number Diff line number Diff line
@@ -51,6 +51,10 @@ enum {
    DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED     = -3,
};

enum {
    EVENT_NOTIFY = 1,
};

struct CryptoErrorCodes {
    jint cryptoErrorNoKey;
    jint cryptoErrorKeyExpired;
@@ -59,6 +63,7 @@ struct CryptoErrorCodes {

struct fields_t {
    jfieldID context;
    jmethodID postEventFromNativeID;
    jfieldID cryptoInfoNumSubSamplesID;
    jfieldID cryptoInfoNumBytesOfClearDataID;
    jfieldID cryptoInfoNumBytesOfEncryptedDataID;
@@ -75,7 +80,9 @@ JMediaCodec::JMediaCodec(
        JNIEnv *env, jobject thiz,
        const char *name, bool nameIsType, bool encoder)
    : mClass(NULL),
      mObject(NULL) {
      mObject(NULL),
      mGeneration(1),
      mRequestedActivityNotification(false) {
    jclass clazz = env->GetObjectClass(thiz);
    CHECK(clazz != NULL);

@@ -87,7 +94,7 @@ JMediaCodec::JMediaCodec(

    mLooper->start(
            false,      // runOnCallingThread
            false,       // canCallJava
            true,       // canCallJava
            PRIORITY_FOREGROUND);

    if (nameIsType) {
@@ -101,6 +108,10 @@ status_t JMediaCodec::initCheck() const {
    return mCodec != NULL ? OK : NO_INIT;
}

void JMediaCodec::registerSelf() {
    mLooper->registerHandler(this);
}

JMediaCodec::~JMediaCodec() {
    if (mCodec != NULL) {
        mCodec->release();
@@ -122,7 +133,8 @@ status_t JMediaCodec::configure(
        int flags) {
    sp<Surface> client;
    if (bufferProducer != NULL) {
        mSurfaceTextureClient = new Surface(bufferProducer, true /* controlledByApp */);
        mSurfaceTextureClient =
            new Surface(bufferProducer, true /* controlledByApp */);
    } else {
        mSurfaceTextureClient.clear();
    }
@@ -136,13 +148,32 @@ status_t JMediaCodec::createInputSurface(
}

status_t JMediaCodec::start() {
    return mCodec->start();
    status_t err = mCodec->start();

    if (err != OK) {
        return err;
    }

    mActivityNotification = new AMessage(kWhatActivityNotify, id());
    mActivityNotification->setInt32("generation", mGeneration);

    requestActivityNotification();

    return err;
}

status_t JMediaCodec::stop() {
    mSurfaceTextureClient.clear();

    return mCodec->stop();
    status_t err = mCodec->stop();

    sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, id());
    sp<AMessage> response;
    msg->postAndAwaitResponse(&response);

    mActivityNotification.clear();

    return err;
}

status_t JMediaCodec::flush() {
@@ -174,7 +205,11 @@ status_t JMediaCodec::queueSecureInputBuffer(
}

status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
    return mCodec->dequeueInputBuffer(index, timeoutUs);
    status_t err = mCodec->dequeueInputBuffer(index, timeoutUs);

    requestActivityNotification();

    return err;
}

status_t JMediaCodec::dequeueOutputBuffer(
@@ -182,9 +217,12 @@ status_t JMediaCodec::dequeueOutputBuffer(
    size_t size, offset;
    int64_t timeUs;
    uint32_t flags;
    status_t err;
    if ((err = mCodec->dequeueOutputBuffer(
                    index, &offset, &size, &timeUs, &flags, timeoutUs)) != OK) {
    status_t err = mCodec->dequeueOutputBuffer(
            index, &offset, &size, &timeUs, &flags, timeoutUs);

    requestActivityNotification();

    if (err != OK) {
        return err;
    }

@@ -320,6 +358,67 @@ void JMediaCodec::setVideoScalingMode(int mode) {
    }
}

void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
        case kWhatRequestActivityNotifications:
        {
            if (mRequestedActivityNotification) {
                break;
            }

            mCodec->requestActivityNotification(mActivityNotification);
            mRequestedActivityNotification = true;
            break;
        }

        case kWhatActivityNotify:
        {
            {
                int32_t generation;
                CHECK(msg->findInt32("generation", &generation));

                if (generation != mGeneration) {
                    // stale
                    break;
                }

                mRequestedActivityNotification = false;
            }

            JNIEnv *env = AndroidRuntime::getJNIEnv();
            env->CallVoidMethod(
                    mObject,
                    gFields.postEventFromNativeID,
                    EVENT_NOTIFY,
                    0 /* arg1 */,
                    0 /* arg2 */,
                    NULL /* obj */);

            break;
        }

        case kWhatStopActivityNotifications:
        {
            uint32_t replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            ++mGeneration;
            mRequestedActivityNotification = false;

            sp<AMessage> response = new AMessage;
            response->postReply(replyID);
            break;
        }

        default:
            TRESPASS();
    }
}

void JMediaCodec::requestActivityNotification() {
    (new AMessage(kWhatRequestActivityNotifications, id()))->post();
}

}  // namespace android

////////////////////////////////////////////////////////////////////////////////
@@ -888,6 +987,12 @@ static void android_media_MediaCodec_native_init(JNIEnv *env) {
    gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
    CHECK(gFields.context != NULL);

    gFields.postEventFromNativeID =
        env->GetMethodID(
                clazz.get(), "postEventFromNative", "(IIILjava/lang/Object;)V");

    CHECK(gFields.postEventFromNativeID != NULL);

    clazz.reset(env->FindClass("android/media/MediaCodec$CryptoInfo"));
    CHECK(clazz.get() != NULL);

@@ -961,6 +1066,8 @@ static void android_media_MediaCodec_native_setup(
        return;
    }

    codec->registerSelf();

    setMediaCodec(env,thiz, codec);
}

@@ -981,7 +1088,7 @@ static JNINativeMethod gMethods[] = {
      (void *)android_media_MediaCodec_createInputSurface },

    { "start", "()V", (void *)android_media_MediaCodec_start },
    { "stop", "()V", (void *)android_media_MediaCodec_stop },
    { "native_stop", "()V", (void *)android_media_MediaCodec_stop },
    { "flush", "()V", (void *)android_media_MediaCodec_flush },

    { "queueInputBuffer", "(IIIJI)V",
+18 −2
Original line number Diff line number Diff line
@@ -21,8 +21,8 @@

#include <media/hardware/CryptoAPI.h>
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AHandler.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>

namespace android {

@@ -34,13 +34,15 @@ struct IGraphicBufferProducer;
struct MediaCodec;
class Surface;

struct JMediaCodec : public RefBase {
struct JMediaCodec : public AHandler {
    JMediaCodec(
            JNIEnv *env, jobject thiz,
            const char *name, bool nameIsType, bool encoder);

    status_t initCheck() const;

    void registerSelf();

    status_t configure(
            const sp<AMessage> &format,
            const sp<IGraphicBufferProducer> &bufferProducer,
@@ -94,7 +96,15 @@ struct JMediaCodec : public RefBase {
protected:
    virtual ~JMediaCodec();

    virtual void onMessageReceived(const sp<AMessage> &msg);

private:
    enum {
        kWhatActivityNotify,
        kWhatRequestActivityNotifications,
        kWhatStopActivityNotifications,
    };

    jclass mClass;
    jweak mObject;
    sp<Surface> mSurfaceTextureClient;
@@ -102,6 +112,12 @@ private:
    sp<ALooper> mLooper;
    sp<MediaCodec> mCodec;

    sp<AMessage> mActivityNotification;
    int32_t mGeneration;
    bool mRequestedActivityNotification;

    void requestActivityNotification();

    DISALLOW_EVIL_CONSTRUCTORS(JMediaCodec);
};