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

Commit 2665ce8f authored by Jin Heo's avatar Jin Heo Committed by Wonsik Kim
Browse files

NdkMediaCodec: Add setOnFrameRenderedCallback

Add new AMediaCodec_setOnFrameRenderedCallback api to be
invoked when an output frame is rendered on the output surface.

Bug: 184115863
Test: cts/media/device-small
Change-Id: I17f43e3f371ea2970c66c6caafde2a8902886b71
parent 701b0a16
Loading
Loading
Loading
Loading
+64 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include <gui/Surface.h>

#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AMessage.h>

#include <media/stagefright/PersistentSurface.h>
@@ -59,6 +60,7 @@ enum {
    kWhatAsyncNotify,
    kWhatRequestActivityNotifications,
    kWhatStopActivityNotifications,
    kWhatFrameRenderedNotify,
};

struct AMediaCodecPersistentSurface : public Surface {
@@ -98,6 +100,11 @@ struct AMediaCodec {
    mutable Mutex mAsyncCallbackLock;
    AMediaCodecOnAsyncNotifyCallback mAsyncCallback;
    void *mAsyncCallbackUserData;

    sp<AMessage> mFrameRenderedNotify;
    mutable Mutex mFrameRenderedCallbackLock;
    AMediaCodecOnFrameRendered mFrameRenderedCallback;
    void *mFrameRenderedCallbackUserData;
};

CodecHandler::CodecHandler(AMediaCodec *codec) {
@@ -294,6 +301,43 @@ void CodecHandler::onMessageReceived(const sp<AMessage> &msg) {
            break;
        }

        case kWhatFrameRenderedNotify:
        {
            sp<AMessage> data;
            if (!msg->findMessage("data", &data)) {
                ALOGE("kWhatFrameRenderedNotify: data is expected.");
                break;
            }

            AMessage::Type type;
            int64_t mediaTimeUs, systemNano;
            size_t index = 0;

            // TODO. This code has dependency with MediaCodec::CreateFramesRenderedMessage.
            for (size_t ix = 0; ix < data->countEntries(); ix++) {
                AString name = data->getEntryNameAt(ix, &type);
                if (name.startsWith(AStringPrintf("%zu-media-time-us", index).c_str())) {
                    AMessage::ItemData data = msg->getEntryAt(index);
                    data.find(&mediaTimeUs);
                } else if (name.startsWith(AStringPrintf("%zu-system-nano", index).c_str())) {
                    AMessage::ItemData data = msg->getEntryAt(index);
                    data.find(&systemNano);

                    Mutex::Autolock _l(mCodec->mFrameRenderedCallbackLock);
                    if (mCodec->mFrameRenderedCallback != NULL) {
                        mCodec->mFrameRenderedCallback(
                                mCodec,
                                mCodec->mFrameRenderedCallbackUserData,
                                mediaTimeUs,
                                systemNano);
                    }

                    index++;
                }
            }
            break;
        }

        default:
            ALOGE("shouldn't be here");
            break;
@@ -490,6 +534,26 @@ media_status_t AMediaCodec_setAsyncNotifyCallback(
    return AMEDIA_OK;
}

EXPORT
media_status_t AMediaCodec_setOnFrameRenderedCallback(
        AMediaCodec *mData,
        AMediaCodecOnFrameRendered callback,
        void *userdata) {
    Mutex::Autolock _l(mData->mFrameRenderedCallbackLock);
    if (mData->mFrameRenderedNotify == NULL) {
        mData->mFrameRenderedNotify = new AMessage(kWhatFrameRenderedNotify, mData->mHandler);
    }
    status_t err = mData->mCodec->setOnFrameRenderedNotification(mData->mFrameRenderedNotify);
    if (err != OK) {
        ALOGE("setOnFrameRenderedNotifyCallback: err(%d), failed to set callback", err);
        return translate_error(err);
    }

    mData->mFrameRenderedCallback = callback;
    mData->mFrameRenderedCallbackUserData = userdata;

    return AMEDIA_OK;
}

EXPORT
media_status_t AMediaCodec_releaseCrypto(AMediaCodec *mData) {
+47 −0
Original line number Diff line number Diff line
@@ -39,6 +39,8 @@
#include <stdint.h>
#include <sys/cdefs.h>

#include <android/api-level.h>

#include "NdkMediaCrypto.h"
#include "NdkMediaError.h"
#include "NdkMediaFormat.h"
@@ -121,6 +123,25 @@ typedef struct AMediaCodecOnAsyncNotifyCallback {
      AMediaCodecOnAsyncError           onAsyncError;
} AMediaCodecOnAsyncNotifyCallback;

/**
 * Called when an output frame has rendered on the output surface.
 *
 * \param codec       The codec object that generated this notification.
 * \param userdata    The user data set at AMediaCodec_setOnFrameRenderedCallback.
 * \param mediaTimeUs The presentation time (media time) of the frame rendered.
 *                    This is usually the same as specified in
 *                    AMediaCodec_queueInputBuffer, but some codecs may alter
 *                    the media time by applying some time-based transformation,
 *                    such as frame rate conversion. In that case, presentation
 *                    time corresponds to the actual output frame rendered.
 * \param systemNano  The system time when the frame was rendered.
 */
typedef void (*AMediaCodecOnFrameRendered)(
        AMediaCodec *codec,
        void *userdata,
        int64_t mediaTimeUs,
        int64_t systemNano);

/**
 * Create codec by name. Use this if you know the exact codec you want to use.
 * When configuring, you will need to specify whether to use the codec as an
@@ -440,6 +461,32 @@ media_status_t AMediaCodec_setAsyncNotifyCallback(
        AMediaCodecOnAsyncNotifyCallback callback,
        void *userdata) __INTRODUCED_IN(28);

/**
 * Registers a callback to be invoked when an output frame is rendered on the output surface.
 *
 * This method can be called in any codec state, but will only have an effect in the
 * Executing state for codecs that render buffers to the output surface.
 *
 * This callback is for informational purposes only: to get precise
 * render timing samples, and can be significantly delayed and batched. Some frames may have
 * been rendered even if there was no callback generated.
 *
 * Refer to the definition of AMediaCodecOnFrameRendered on how each
 * callback function is called and what are specified.
 * The specified userdata is the pointer used when those callback functions are
 * called.
 *
 * All callbacks are fired on one NDK internal thread.
 * AMediaCodec_setOnFrameRenderedCallback should not be called on the callback thread.
 * No heavy duty task should be performed on callback thread.
 *
 * Available since Android T.
 */
media_status_t AMediaCodec_setOnFrameRenderedCallback(
        AMediaCodec*,
        AMediaCodecOnFrameRendered callback,
        void *userdata) __INTRODUCED_IN(__ANDROID_API_T__);

/**
 * Release the crypto if applicable.
 *
+1 −0
Original line number Diff line number Diff line
@@ -203,6 +203,7 @@ LIBMEDIANDK {
    AMediaCodec_releaseOutputBuffer;
    AMediaCodec_releaseOutputBufferAtTime;
    AMediaCodec_setAsyncNotifyCallback; # introduced=28
    AMediaCodec_setOnFrameRenderedCallback; # introduced=Tiramisu
    AMediaCodec_setOutputSurface; # introduced=24
    AMediaCodec_setParameters; # introduced=26
    AMediaCodec_setInputSurface; # introduced=26