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

Commit 4f576188 authored by Guillaume Chelfi's avatar Guillaume Chelfi Committed by Android (Google) Code Review
Browse files

Merge "Add tunnel mode video peek related APIs" into sc-dev

parents 6c5499ec c072caf1
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -21341,6 +21341,7 @@ package android.media {
    method public void setCallback(@Nullable android.media.MediaCodec.Callback, @Nullable android.os.Handler);
    method public void setCallback(@Nullable android.media.MediaCodec.Callback);
    method public void setInputSurface(@NonNull android.view.Surface);
    method public void setOnFirstTunnelFrameReadyListener(@Nullable android.os.Handler, @Nullable android.media.MediaCodec.OnFirstTunnelFrameReadyListener);
    method public void setOnFrameRenderedListener(@Nullable android.media.MediaCodec.OnFrameRenderedListener, @Nullable android.os.Handler);
    method public void setOutputSurface(@NonNull android.view.Surface);
    method public void setParameters(@Nullable android.os.Bundle);
@@ -21368,6 +21369,7 @@ package android.media {
    field public static final String PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
    field public static final String PARAMETER_KEY_SUSPEND = "drop-input-frames";
    field public static final String PARAMETER_KEY_SUSPEND_TIME = "drop-start-time-us";
    field public static final String PARAMETER_KEY_TUNNEL_PEEK = "tunnel-peek";
    field public static final String PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
    field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1
    field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
@@ -21458,6 +21460,10 @@ package android.media {
    field public static final String WIDTH = "android.media.mediacodec.width";
  }
  public static interface MediaCodec.OnFirstTunnelFrameReadyListener {
    method public void onFirstTunnelFrameReady(@NonNull android.media.MediaCodec);
  }
  public static interface MediaCodec.OnFrameRenderedListener {
    method public void onFrameRendered(@NonNull android.media.MediaCodec, long, long);
  }
+103 −0
Original line number Diff line number Diff line
@@ -1674,9 +1674,11 @@ final public class MediaCodec implements PlaybackComponent {
    public @interface BufferFlag {}

    private EventHandler mEventHandler;
    private EventHandler mOnFirstTunnelFrameReadyHandler;
    private EventHandler mOnFrameRenderedHandler;
    private EventHandler mCallbackHandler;
    private Callback mCallback;
    private OnFirstTunnelFrameReadyListener mOnFirstTunnelFrameReadyListener;
    private OnFrameRenderedListener mOnFrameRenderedListener;
    private final Object mListenerLock = new Object();
    private MediaCodecInfo mCodecInfo;
@@ -1687,6 +1689,7 @@ final public class MediaCodec implements PlaybackComponent {
    private static final int EVENT_CALLBACK = 1;
    private static final int EVENT_SET_CALLBACK = 2;
    private static final int EVENT_FRAME_RENDERED = 3;
    private static final int EVENT_FIRST_TUNNEL_FRAME_READY = 4;

    private static final int CB_INPUT_AVAILABLE = 1;
    private static final int CB_OUTPUT_AVAILABLE = 2;
@@ -1748,6 +1751,16 @@ final public class MediaCodec implements PlaybackComponent {
                                mCodec, (long)mediaTimeUs, (long)systemNano);
                    }
                    break;
                case EVENT_FIRST_TUNNEL_FRAME_READY:
                    OnFirstTunnelFrameReadyListener onFirstTunnelFrameReadyListener;
                    synchronized (mListenerLock) {
                        onFirstTunnelFrameReadyListener = mOnFirstTunnelFrameReadyListener;
                    }
                    if (onFirstTunnelFrameReadyListener == null) {
                        break;
                    }
                    onFirstTunnelFrameReadyListener.onFirstTunnelFrameReady(mCodec);
                    break;
                default:
                {
                    break;
@@ -1923,6 +1936,7 @@ final public class MediaCodec implements PlaybackComponent {
            mEventHandler = null;
        }
        mCallbackHandler = mEventHandler;
        mOnFirstTunnelFrameReadyHandler = mEventHandler;
        mOnFrameRenderedHandler = mEventHandler;

        mBufferLock = new Object();
@@ -2277,6 +2291,9 @@ final public class MediaCodec implements PlaybackComponent {
                mCallbackHandler.removeMessages(EVENT_SET_CALLBACK);
                mCallbackHandler.removeMessages(EVENT_CALLBACK);
            }
            if (mOnFirstTunnelFrameReadyHandler != null) {
                mOnFirstTunnelFrameReadyHandler.removeMessages(EVENT_FIRST_TUNNEL_FRAME_READY);
            }
            if (mOnFrameRenderedHandler != null) {
                mOnFrameRenderedHandler.removeMessages(EVENT_FRAME_RENDERED);
            }
@@ -4446,6 +4463,41 @@ final public class MediaCodec implements PlaybackComponent {
    public static final String PARAMETER_KEY_LOW_LATENCY =
            MediaFormat.KEY_LOW_LATENCY;

    /**
     * Control video peek of the first frame when a codec is configured for tunnel mode with
     * {@link MediaFormat#KEY_AUDIO_SESSION_ID} while the {@link AudioTrack} is paused.
     *<p>
     * When disabled (1) after a {@link #flush} or {@link #start}, (2) while the corresponding
     * {@link AudioTrack} is paused and (3) before any buffers are queued, the first frame is not to
     * be rendered until either this parameter is enabled or the corresponding {@link AudioTrack}
     * has begun playback. Once the frame is decoded and ready to be rendered,
     * {@link OnFirstTunnelFrameReadyListener#onFirstTunnelFrameReady} is called but the frame is
     * not rendered. The surface continues to show the previously-rendered content, or black if the
     * surface is new. A subsequent call to {@link AudioTrack#play} renders this frame and triggers
     * a callback to {@link OnFrameRenderedListener#onFrameRendered}, and video playback begins.
     *<p>
     * <b>Note</b>: To clear any previously rendered content and show black, configure the
     * MediaCodec with {@code KEY_PUSH_BLANK_BUFFERS_ON_STOP(1)}, and call {@link #stop} before
     * pushing new video frames to the codec.
     *<p>
     * When enabled (1) after a {@link #flush} or {@link #start} and (2) while the corresponding
     * {@link AudioTrack} is paused, the first frame is rendered as soon as it is decoded, or
     * immediately, if it has already been decoded. If not already decoded, when the frame is
     * decoded and ready to be rendered,
     * {@link OnFirstTunnelFrameReadyListener#onFirstTunnelFrameReady} is called. The frame is then
     * immediately rendered and {@link OnFrameRenderedListener#onFrameRendered} is subsequently
     * called.
     *<p>
     * The value is an Integer object containing the value 1 to enable or the value 0 to disable.
     *<p>
     * The default for this parameter is <b>enabled</b>. Once a frame has been rendered, changing
     * this parameter has no effect until a subsequent {@link #flush} or
     * {@link #stop}/{@link #start}.
     *
     * @see #setParameters(Bundle)
     */
    public static final String PARAMETER_KEY_TUNNEL_PEEK = "tunnel-peek";

    /**
     * Communicate additional parameter changes to the component instance.
     * <b>Note:</b> Some of these parameter changes may silently fail to apply.
@@ -4544,6 +4596,55 @@ final public class MediaCodec implements PlaybackComponent {
        setCallback(cb, null /* handler */);
    }

    /**
     * Listener to be called when the first output frame has been decoded
     * and is ready to be rendered for a codec configured for tunnel mode with
     * {@code KEY_AUDIO_SESSION_ID}.
     *
     * @see MediaCodec#setOnFirstTunnelFrameReadyListener
     */
    public interface OnFirstTunnelFrameReadyListener {

        /**
         * Called when the first output frame has been decoded and is ready to be
         * rendered.
         */
        void onFirstTunnelFrameReady(@NonNull MediaCodec codec);
    }

    /**
     * Registers a callback to be invoked when the first output frame has been decoded
     * and is ready to be rendered on a codec configured for tunnel mode with {@code
     * KEY_AUDIO_SESSION_ID}.
     *
     * @param handler the callback will be run on the handler's thread. If {@code
     * null}, the callback will be run on the default thread, which is the looper from
     * which the codec was created, or a new thread if there was none.
     *
     * @param listener the callback that will be run. If {@code null}, clears any registered
     * listener.
     */
    public void setOnFirstTunnelFrameReadyListener(
            @Nullable Handler handler, @Nullable OnFirstTunnelFrameReadyListener listener) {
        synchronized (mListenerLock) {
            mOnFirstTunnelFrameReadyListener = listener;
            if (listener != null) {
                EventHandler newHandler = getEventHandlerOn(
                        handler,
                        mOnFirstTunnelFrameReadyHandler);
                if (newHandler != mOnFirstTunnelFrameReadyHandler) {
                    mOnFirstTunnelFrameReadyHandler.removeMessages(EVENT_FIRST_TUNNEL_FRAME_READY);
                }
                mOnFirstTunnelFrameReadyHandler = newHandler;
            } else if (mOnFirstTunnelFrameReadyHandler != null) {
                mOnFirstTunnelFrameReadyHandler.removeMessages(EVENT_FIRST_TUNNEL_FRAME_READY);
            }
            native_enableOnFirstTunnelFrameReadyListener(listener != null);
        }
    }

    private native void native_enableOnFirstTunnelFrameReadyListener(boolean enable);

    /**
     * Listener to be called when an output frame has rendered on the output surface
     *
@@ -4667,6 +4768,8 @@ final public class MediaCodec implements PlaybackComponent {
            EventHandler handler = mEventHandler;
            if (what == EVENT_CALLBACK) {
                handler = mCallbackHandler;
            } else if (what == EVENT_FIRST_TUNNEL_FRAME_READY) {
                handler = mOnFirstTunnelFrameReadyHandler;
            } else if (what == EVENT_FRAME_RENDERED) {
                handler = mOnFrameRenderedHandler;
            }
+58 −0
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ enum {
    EVENT_CALLBACK = 1,
    EVENT_SET_CALLBACK = 2,
    EVENT_FRAME_RENDERED = 3,
    EVENT_FIRST_TUNNEL_FRAME_READY = 4,
};

static struct CryptoErrorCodes {
@@ -269,6 +270,18 @@ JMediaCodec::~JMediaCodec() {
    mClass = NULL;
}

status_t JMediaCodec::enableOnFirstTunnelFrameReadyListener(jboolean enable) {
    if (enable) {
        if (mOnFirstTunnelFrameReadyNotification == NULL) {
            mOnFirstTunnelFrameReadyNotification = new AMessage(kWhatFirstTunnelFrameReady, this);
        }
    } else {
        mOnFirstTunnelFrameReadyNotification.clear();
    }

    return mCodec->setOnFirstTunnelFrameReadyNotification(mOnFirstTunnelFrameReadyNotification);
}

status_t JMediaCodec::enableOnFrameRenderedListener(jboolean enable) {
    if (enable) {
        if (mOnFrameRenderedNotification == NULL) {
@@ -1058,6 +1071,27 @@ void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
    env->DeleteLocalRef(obj);
}

void JMediaCodec::handleFirstTunnelFrameReadyNotification(const sp<AMessage> &msg) {
    int32_t arg1 = 0, arg2 = 0;
    jobject obj = NULL;
    JNIEnv *env = AndroidRuntime::getJNIEnv();

    sp<AMessage> data;
    CHECK(msg->findMessage("data", &data));

    status_t err = ConvertMessageToMap(env, data, &obj);
    if (err != OK) {
        jniThrowException(env, "java/lang/IllegalStateException", NULL);
        return;
    }

    env->CallVoidMethod(
            mObject, gFields.postEventFromNativeID,
            EVENT_FIRST_TUNNEL_FRAME_READY, arg1, arg2, obj);

    env->DeleteLocalRef(obj);
}

void JMediaCodec::handleFrameRenderedNotification(const sp<AMessage> &msg) {
    int32_t arg1 = 0, arg2 = 0;
    jobject obj = NULL;
@@ -1100,6 +1134,11 @@ void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
            }
            break;
        }
        case kWhatFirstTunnelFrameReady:
        {
            handleFirstTunnelFrameReadyNotification(msg);
            break;
        }
        default:
            TRESPASS();
    }
@@ -1256,6 +1295,22 @@ static jint throwExceptionAsNecessary(
    }
}

static void android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener(
        JNIEnv *env,
        jobject thiz,
        jboolean enabled) {
    sp<JMediaCodec> codec = getMediaCodec(env, thiz);

    if (codec == NULL || codec->initCheck() != OK) {
        throwExceptionAsNecessary(env, INVALID_OPERATION);
        return;
    }

    status_t err = codec->enableOnFirstTunnelFrameReadyListener(enabled);

    throwExceptionAsNecessary(env, err);
}

static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
        JNIEnv *env,
        jobject thiz,
@@ -3138,6 +3193,9 @@ static const JNINativeMethod gMethods[] = {
    { "native_setInputSurface", "(Landroid/view/Surface;)V",
      (void *)android_media_MediaCodec_setInputSurface },

    { "native_enableOnFirstTunnelFrameReadyListener", "(Z)V",
      (void *)android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener },

    { "native_enableOnFrameRenderedListener", "(Z)V",
      (void *)android_media_MediaCodec_native_enableOnFrameRenderedListener },

+5 −0
Original line number Diff line number Diff line
@@ -63,6 +63,8 @@ struct JMediaCodec : public AHandler {
    void release();
    void releaseAsync();

    status_t enableOnFirstTunnelFrameReadyListener(jboolean enable);

    status_t enableOnFrameRenderedListener(jboolean enable);

    status_t setCallback(jobject cb);
@@ -176,6 +178,7 @@ private:
        kWhatCallbackNotify,
        kWhatFrameRendered,
        kWhatAsyncReleaseComplete,
        kWhatFirstTunnelFrameReady,
    };

    jclass mClass;
@@ -191,6 +194,7 @@ private:
    std::once_flag mAsyncReleaseFlag;

    sp<AMessage> mCallbackNotification;
    sp<AMessage> mOnFirstTunnelFrameReadyNotification;
    sp<AMessage> mOnFrameRenderedNotification;

    status_t mInitStatus;
@@ -203,6 +207,7 @@ private:
            jobject *buf) const;

    void handleCallback(const sp<AMessage> &msg);
    void handleFirstTunnelFrameReadyNotification(const sp<AMessage> &msg);
    void handleFrameRenderedNotification(const sp<AMessage> &msg);

    DISALLOW_EVIL_CONSTRUCTORS(JMediaCodec);