Loading media/ndk/NdkMediaCodec.cpp +64 −0 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -59,6 +60,7 @@ enum { kWhatAsyncNotify, kWhatRequestActivityNotifications, kWhatStopActivityNotifications, kWhatFrameRenderedNotify, }; struct AMediaCodecPersistentSurface : public Surface { Loading Loading @@ -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) { Loading Loading @@ -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; Loading Loading @@ -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) { Loading media/ndk/include/media/NdkMediaCodec.h +47 −0 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -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 Loading Loading @@ -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. * Loading media/ndk/libmediandk.map.txt +1 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading
media/ndk/NdkMediaCodec.cpp +64 −0 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -59,6 +60,7 @@ enum { kWhatAsyncNotify, kWhatRequestActivityNotifications, kWhatStopActivityNotifications, kWhatFrameRenderedNotify, }; struct AMediaCodecPersistentSurface : public Surface { Loading Loading @@ -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) { Loading Loading @@ -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; Loading Loading @@ -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) { Loading
media/ndk/include/media/NdkMediaCodec.h +47 −0 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -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 Loading Loading @@ -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. * Loading
media/ndk/libmediandk.map.txt +1 −0 Original line number Diff line number Diff line Loading @@ -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 Loading