Loading media/ndk/NdkMediaCodec.cpp +254 −3 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ static media_status_t translate_error(status_t err) { enum { kWhatActivityNotify, kWhatAsyncNotify, kWhatRequestActivityNotifications, kWhatStopActivityNotifications, }; Loading Loading @@ -88,6 +89,11 @@ struct AMediaCodec { bool mRequestedActivityNotification; OnCodecEvent mCallback; void *mCallbackUserData; sp<AMessage> mAsyncNotify; mutable Mutex mAsyncCallbackLock; AMediaCodecOnAsyncNotifyCallback mAsyncCallback; void *mAsyncCallbackUserData; }; CodecHandler::CodecHandler(AMediaCodec *codec) { Loading Loading @@ -128,6 +134,147 @@ void CodecHandler::onMessageReceived(const sp<AMessage> &msg) { break; } case kWhatAsyncNotify: { int32_t cbID; if (!msg->findInt32("callbackID", &cbID)) { ALOGE("kWhatAsyncNotify: callbackID is expected."); break; } ALOGV("kWhatAsyncNotify: cbID = %d", cbID); switch (cbID) { case MediaCodec::CB_INPUT_AVAILABLE: { int32_t index; if (!msg->findInt32("index", &index)) { ALOGE("CB_INPUT_AVAILABLE: index is expected."); break; } Mutex::Autolock _l(mCodec->mAsyncCallbackLock); if (mCodec->mAsyncCallbackUserData != NULL || mCodec->mAsyncCallback.onAsyncInputAvailable != NULL) { mCodec->mAsyncCallback.onAsyncInputAvailable( mCodec, mCodec->mAsyncCallbackUserData, index); } break; } case MediaCodec::CB_OUTPUT_AVAILABLE: { int32_t index; size_t offset; size_t size; int64_t timeUs; int32_t flags; if (!msg->findInt32("index", &index)) { ALOGE("CB_OUTPUT_AVAILABLE: index is expected."); break; } if (!msg->findSize("offset", &offset)) { ALOGE("CB_OUTPUT_AVAILABLE: offset is expected."); break; } if (!msg->findSize("size", &size)) { ALOGE("CB_OUTPUT_AVAILABLE: size is expected."); break; } if (!msg->findInt64("timeUs", &timeUs)) { ALOGE("CB_OUTPUT_AVAILABLE: timeUs is expected."); break; } if (!msg->findInt32("flags", &flags)) { ALOGE("CB_OUTPUT_AVAILABLE: flags is expected."); break; } AMediaCodecBufferInfo bufferInfo = { (int32_t)offset, (int32_t)size, timeUs, (uint32_t)flags}; Mutex::Autolock _l(mCodec->mAsyncCallbackLock); if (mCodec->mAsyncCallbackUserData != NULL || mCodec->mAsyncCallback.onAsyncOutputAvailable != NULL) { mCodec->mAsyncCallback.onAsyncOutputAvailable( mCodec, mCodec->mAsyncCallbackUserData, index, &bufferInfo); } break; } case MediaCodec::CB_OUTPUT_FORMAT_CHANGED: { sp<AMessage> format; if (!msg->findMessage("format", &format)) { ALOGE("CB_OUTPUT_FORMAT_CHANGED: format is expected."); break; } AMediaFormat *aMediaFormat = AMediaFormat_fromMsg(&format); Mutex::Autolock _l(mCodec->mAsyncCallbackLock); if (mCodec->mAsyncCallbackUserData != NULL || mCodec->mAsyncCallback.onAsyncFormatChanged != NULL) { mCodec->mAsyncCallback.onAsyncFormatChanged( mCodec, mCodec->mAsyncCallbackUserData, aMediaFormat); } break; } case MediaCodec::CB_ERROR: { status_t err; int32_t actionCode; AString detail; if (!msg->findInt32("err", &err)) { ALOGE("CB_ERROR: err is expected."); break; } if (!msg->findInt32("action", &actionCode)) { ALOGE("CB_ERROR: action is expected."); break; } msg->findString("detail", &detail); ALOGE("Decoder reported error(0x%x), actionCode(%d), detail(%s)", err, actionCode, detail.c_str()); Mutex::Autolock _l(mCodec->mAsyncCallbackLock); if (mCodec->mAsyncCallbackUserData != NULL || mCodec->mAsyncCallback.onAsyncError != NULL) { mCodec->mAsyncCallback.onAsyncError( mCodec, mCodec->mAsyncCallbackUserData, translate_error(err), actionCode, detail.c_str()); } break; } default: { ALOGE("kWhatAsyncNotify: callbackID(%d) is unexpected.", cbID); break; } } break; } case kWhatStopActivityNotifications: { sp<AReplyToken> replyID; Loading Loading @@ -162,7 +309,7 @@ static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool size_t res = mData->mLooper->start( false, // runOnCallingThread true, // canCallJava XXX PRIORITY_FOREGROUND); PRIORITY_AUDIO); if (res != OK) { ALOGE("Failed to start the looper"); AMediaCodec_delete(mData); Loading @@ -183,6 +330,9 @@ static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool mData->mRequestedActivityNotification = false; mData->mCallback = NULL; mData->mAsyncCallback = {}; mData->mAsyncCallbackUserData = NULL; return mData; } Loading Loading @@ -221,6 +371,32 @@ media_status_t AMediaCodec_delete(AMediaCodec *mData) { return AMEDIA_OK; } EXPORT media_status_t AMediaCodec_getName( AMediaCodec *mData, char** out_name) { if (out_name == NULL) { return AMEDIA_ERROR_INVALID_PARAMETER; } AString compName; status_t err = mData->mCodec->getName(&compName); if (err != OK) { return translate_error(err); } *out_name = strdup(compName.c_str()); return AMEDIA_OK; } EXPORT void AMediaCodec_releaseName( AMediaCodec * /* mData */, char* name) { if (name != NULL) { free(name); } } EXPORT media_status_t AMediaCodec_configure( AMediaCodec *mData, Loading @@ -236,8 +412,40 @@ media_status_t AMediaCodec_configure( surface = (Surface*) window; } return translate_error(mData->mCodec->configure(nativeFormat, surface, crypto ? crypto->mCrypto : NULL, flags)); status_t err = mData->mCodec->configure(nativeFormat, surface, crypto ? crypto->mCrypto : NULL, flags); if (err != OK) { ALOGE("configure: err(%d), failed with format: %s", err, nativeFormat->debugString(0).c_str()); } return translate_error(err); } EXPORT media_status_t AMediaCodec_setAsyncNotifyCallback( AMediaCodec *mData, AMediaCodecOnAsyncNotifyCallback callback, void *userdata) { if (mData->mAsyncNotify == NULL && userdata != NULL) { mData->mAsyncNotify = new AMessage(kWhatAsyncNotify, mData->mHandler); status_t err = mData->mCodec->setCallback(mData->mAsyncNotify); if (err != OK) { ALOGE("setAsyncNotifyCallback: err(%d), failed to set async callback", err); return translate_error(err); } } Mutex::Autolock _l(mData->mAsyncCallbackLock); mData->mAsyncCallback = callback; mData->mAsyncCallbackUserData = userdata; return AMEDIA_OK; } EXPORT media_status_t AMediaCodec_releaseCrypto(AMediaCodec *mData) { return translate_error(mData->mCodec->releaseCrypto()); } EXPORT Loading Loading @@ -282,6 +490,19 @@ ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) { EXPORT uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) { if (mData->mAsyncNotify != NULL) { // Asynchronous mode sp<MediaCodecBuffer> abuf; if (mData->mCodec->getInputBuffer(idx, &abuf) != 0) { return NULL; } if (out_size != NULL) { *out_size = abuf->capacity(); } return abuf->data(); } android::Vector<android::sp<android::MediaCodecBuffer> > abufs; if (mData->mCodec->getInputBuffers(&abufs) == 0) { size_t n = abufs.size(); Loading @@ -304,6 +525,19 @@ uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_ EXPORT uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) { if (mData->mAsyncNotify != NULL) { // Asynchronous mode sp<MediaCodecBuffer> abuf; if (mData->mCodec->getOutputBuffer(idx, &abuf) != 0) { return NULL; } if (out_size != NULL) { *out_size = abuf->capacity(); } return abuf->data(); } android::Vector<android::sp<android::MediaCodecBuffer> > abufs; if (mData->mCodec->getOutputBuffers(&abufs) == 0) { size_t n = abufs.size(); Loading Loading @@ -366,6 +600,13 @@ AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) { return AMediaFormat_fromMsg(&format); } EXPORT AMediaFormat* AMediaCodec_getInputFormat(AMediaCodec *mData) { sp<AMessage> format; mData->mCodec->getInputFormat(&format); return AMediaFormat_fromMsg(&format); } EXPORT AMediaFormat* AMediaCodec_getBufferFormat(AMediaCodec *mData, size_t index) { sp<AMessage> format; Loading Loading @@ -542,6 +783,16 @@ media_status_t AMediaCodec_queueSecureInputBuffer( return translate_error(err); } EXPORT bool AMediaCodecActionCode_isRecoverable(int32_t actionCode) { return (actionCode == ACTION_CODE_RECOVERABLE); } EXPORT bool AMediaCodecActionCode_isTransient(int32_t actionCode) { return (actionCode == ACTION_CODE_TRANSIENT); } EXPORT void AMediaCodecCryptoInfo_setPattern(AMediaCodecCryptoInfo *info, Loading media/ndk/NdkMediaFormat.cpp +67 −1 Original line number Diff line number Diff line Loading @@ -125,6 +125,14 @@ const char* AMediaFormat_toString(AMediaFormat *mData) { ret.appendFormat("double(%f)", val); break; } case AMessage::kTypeRect: { int32_t left, top, right, bottom; f->findRect(name, &left, &top, &right, &bottom); ret.appendFormat("Rect(%" PRId32 ", %" PRId32 ", %" PRId32 ", %" PRId32 ")", left, top, right, bottom); break; } case AMessage::kTypeString: { AString val; Loading Loading @@ -164,11 +172,22 @@ bool AMediaFormat_getFloat(AMediaFormat* format, const char *name, float *out) { return format->mFormat->findFloat(name, out); } EXPORT bool AMediaFormat_getDouble(AMediaFormat* format, const char *name, double *out) { return format->mFormat->findDouble(name, out); } EXPORT bool AMediaFormat_getSize(AMediaFormat* format, const char *name, size_t *out) { return format->mFormat->findSize(name, out); } EXPORT bool AMediaFormat_getRect(AMediaFormat* format, const char *name, int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) { return format->mFormat->findRect(name, left, top, right, bottom); } EXPORT bool AMediaFormat_getBuffer(AMediaFormat* format, const char *name, void** data, size_t *outsize) { sp<ABuffer> buf; Loading Loading @@ -215,6 +234,22 @@ void AMediaFormat_setFloat(AMediaFormat* format, const char* name, float value) format->mFormat->setFloat(name, value); } EXPORT void AMediaFormat_setDouble(AMediaFormat* format, const char* name, double value) { format->mFormat->setDouble(name, value); } EXPORT void AMediaFormat_setSize(AMediaFormat* format, const char* name, size_t value) { format->mFormat->setSize(name, value); } EXPORT void AMediaFormat_setRect(AMediaFormat* format, const char *name, int32_t left, int32_t top, int32_t right, int32_t bottom) { format->mFormat->setRect(name, left, top, right, bottom); } EXPORT void AMediaFormat_setString(AMediaFormat* format, const char* name, const char* value) { // AMessage::setString() makes a copy of the string Loading @@ -233,30 +268,61 @@ void AMediaFormat_setBuffer(AMediaFormat* format, const char* name, void* data, } EXPORT const char* AMEDIAFORMAT_KEY_AAC_DRC_ATTENUATION_FACTOR = "aac-drc-cut-level"; EXPORT const char* AMEDIAFORMAT_KEY_AAC_DRC_BOOST_FACTOR = "aac-drc-boost-level"; EXPORT const char* AMEDIAFORMAT_KEY_AAC_DRC_HEAVY_COMPRESSION = "aac-drc-heavy-compression"; EXPORT const char* AMEDIAFORMAT_KEY_AAC_DRC_TARGET_REFERENCE_LEVEL = "aac-target-ref-level"; EXPORT const char* AMEDIAFORMAT_KEY_AAC_ENCODED_TARGET_LEVEL = "aac-encoded-target-level"; EXPORT const char* AMEDIAFORMAT_KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count"; EXPORT const char* AMEDIAFORMAT_KEY_AAC_PROFILE = "aac-profile"; EXPORT const char* AMEDIAFORMAT_KEY_AAC_SBR_MODE = "aac-sbr-mode"; EXPORT const char* AMEDIAFORMAT_KEY_AUDIO_SESSION_ID = "audio-session-id"; EXPORT const char* AMEDIAFORMAT_KEY_BITRATE_MODE = "bitrate-mode"; EXPORT const char* AMEDIAFORMAT_KEY_BIT_RATE = "bitrate"; EXPORT const char* AMEDIAFORMAT_KEY_CAPTURE_RATE = "capture-rate"; EXPORT const char* AMEDIAFORMAT_KEY_CHANNEL_COUNT = "channel-count"; EXPORT const char* AMEDIAFORMAT_KEY_CHANNEL_MASK = "channel-mask"; EXPORT const char* AMEDIAFORMAT_KEY_COLOR_FORMAT = "color-format"; EXPORT const char* AMEDIAFORMAT_KEY_COLOR_RANGE = "color-range"; EXPORT const char* AMEDIAFORMAT_KEY_COLOR_STANDARD = "color-standard"; EXPORT const char* AMEDIAFORMAT_KEY_COLOR_TRANSFER = "color-transfer"; EXPORT const char* AMEDIAFORMAT_KEY_COMPLEXITY = "complexity"; EXPORT const char* AMEDIAFORMAT_KEY_DISPLAY_CROP = "crop"; EXPORT const char* AMEDIAFORMAT_KEY_DURATION = "durationUs"; EXPORT const char* AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level"; EXPORT const char* AMEDIAFORMAT_KEY_FRAME_RATE = "frame-rate"; EXPORT const char* AMEDIAFORMAT_KEY_GRID_COLS = "grid-cols"; EXPORT const char* AMEDIAFORMAT_KEY_GRID_HEIGHT = "grid-height"; EXPORT const char* AMEDIAFORMAT_KEY_GRID_ROWS = "grid-rows"; EXPORT const char* AMEDIAFORMAT_KEY_GRID_WIDTH = "grid-width"; EXPORT const char* AMEDIAFORMAT_KEY_HDR_STATIC_INFO = "hdr-static-info"; EXPORT const char* AMEDIAFORMAT_KEY_HEIGHT = "height"; EXPORT const char* AMEDIAFORMAT_KEY_INTRA_REFRESH_PERIOD = "intra-refresh-period"; EXPORT const char* AMEDIAFORMAT_KEY_IS_ADTS = "is-adts"; EXPORT const char* AMEDIAFORMAT_KEY_IS_AUTOSELECT = "is-autoselect"; EXPORT const char* AMEDIAFORMAT_KEY_IS_DEFAULT = "is-default"; EXPORT const char* AMEDIAFORMAT_KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle"; EXPORT const char* AMEDIAFORMAT_KEY_I_FRAME_INTERVAL = "i-frame-interval"; EXPORT const char* AMEDIAFORMAT_KEY_LANGUAGE = "language"; EXPORT const char* AMEDIAFORMAT_KEY_LATENCY = "latency"; EXPORT const char* AMEDIAFORMAT_KEY_LEVEL = "level"; EXPORT const char* AMEDIAFORMAT_KEY_MAX_HEIGHT = "max-height"; EXPORT const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE = "max-input-size"; EXPORT const char* AMEDIAFORMAT_KEY_MAX_WIDTH = "max-width"; EXPORT const char* AMEDIAFORMAT_KEY_MIME = "mime"; EXPORT const char* AMEDIAFORMAT_KEY_OPERATING_RATE = "operating-rate"; EXPORT const char* AMEDIAFORMAT_KEY_PCM_ENCODING = "pcm-encoding"; EXPORT const char* AMEDIAFORMAT_KEY_PRIORITY = "priority"; EXPORT const char* AMEDIAFORMAT_KEY_PROFILE = "profile"; EXPORT const char* AMEDIAFORMAT_KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown"; EXPORT const char* AMEDIAFORMAT_KEY_REPEAT_PREVIOUS_FRAME_AFTER = "repeat-previous-frame-after"; EXPORT const char* AMEDIAFORMAT_KEY_ROTATION = "rotation-degrees"; EXPORT const char* AMEDIAFORMAT_KEY_SAMPLE_RATE = "sample-rate"; EXPORT const char* AMEDIAFORMAT_KEY_WIDTH = "width"; EXPORT const char* AMEDIAFORMAT_KEY_SLICE_HEIGHT = "slice-height"; EXPORT const char* AMEDIAFORMAT_KEY_STRIDE = "stride"; EXPORT const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYERING = "ts-schema"; EXPORT const char* AMEDIAFORMAT_KEY_TRACK_ID = "track-id"; EXPORT const char* AMEDIAFORMAT_KEY_WIDTH = "width"; } // extern "C" Loading media/ndk/include/media/NdkMediaCodec.h +118 −1 Original line number Diff line number Diff line Loading @@ -53,11 +53,63 @@ typedef struct AMediaCodecBufferInfo AMediaCodecBufferInfo; typedef struct AMediaCodecCryptoInfo AMediaCodecCryptoInfo; enum { AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG = 2, AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM = 4, AMEDIACODEC_BUFFER_FLAG_PARTIAL_FRAME = 8, AMEDIACODEC_CONFIGURE_FLAG_ENCODE = 1, AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED = -3, AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED = -2, AMEDIACODEC_INFO_TRY_AGAIN_LATER = -1 AMEDIACODEC_INFO_TRY_AGAIN_LATER = -1, }; /** * Called when an input buffer becomes available. * The specified index is the index of the available input buffer. */ typedef void (*AMediaCodecOnAsyncInputAvailable)( AMediaCodec *codec, void *userdata, int32_t index); /** * Called when an output buffer becomes available. * The specified index is the index of the available output buffer. * The specified bufferInfo contains information regarding the available output buffer. */ typedef void (*AMediaCodecOnAsyncOutputAvailable)( AMediaCodec *codec, void *userdata, int32_t index, AMediaCodecBufferInfo *bufferInfo); /** * Called when the output format has changed. * The specified format contains the new output format. */ typedef void (*AMediaCodecOnAsyncFormatChanged)( AMediaCodec *codec, void *userdata, AMediaFormat *format); /** * Called when the MediaCodec encountered an error. * The specified actionCode indicates the possible actions that client can take, * and it can be checked by calling AMediaCodecActionCode_isRecoverable or * AMediaCodecActionCode_isTransient. If both AMediaCodecActionCode_isRecoverable() * and AMediaCodecActionCode_isTransient() return false, then the codec error is fatal * and the codec must be deleted. * The specified detail may contain more detailed messages about this error. */ typedef void (*AMediaCodecOnAsyncError)( AMediaCodec *codec, void *userdata, media_status_t error, int32_t actionCode, const char *detail); struct AMediaCodecOnAsyncNotifyCallback { AMediaCodecOnAsyncInputAvailable onAsyncInputAvailable; AMediaCodecOnAsyncOutputAvailable onAsyncOutputAvailable; AMediaCodecOnAsyncFormatChanged onAsyncFormatChanged; AMediaCodecOnAsyncError onAsyncError; }; #if __ANDROID_API__ >= 21 Loading Loading @@ -289,6 +341,71 @@ media_status_t AMediaCodec_signalEndOfInputStream(AMediaCodec *mData); #endif /* __ANDROID_API__ >= 26 */ #if __ANDROID_API__ >= 28 /** * Get the component name. If the codec was created by createDecoderByType * or createEncoderByType, what component is chosen is not known beforehand. * Caller shall call AMediaCodec_releaseName to free the returned pointer. */ media_status_t AMediaCodec_getName(AMediaCodec*, char** out_name); /** * Free the memory pointed by name which is returned by AMediaCodec_getName. */ void AMediaCodec_releaseName(AMediaCodec*, char* name); /** * Set an asynchronous callback for actionable AMediaCodec events. * When asynchronous callback is enabled, the client should not call * AMediaCodec_getInputBuffers(), AMediaCodec_getOutputBuffers(), * AMediaCodec_dequeueInputBuffer() or AMediaCodec_dequeueOutputBuffer(). * * Also, AMediaCodec_flush() behaves differently in asynchronous mode. * After calling AMediaCodec_flush(), you must call AMediaCodec_start() to * "resume" receiving input buffers, even if an input surface was created. * * Refer to the definition of AMediaCodecOnAsyncNotifyCallback 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_setAsyncNotifyCallback should not be called on the callback thread. * No heavy duty task should be performed on callback thread. */ media_status_t AMediaCodec_setAsyncNotifyCallback( AMediaCodec*, AMediaCodecOnAsyncNotifyCallback callback, void *userdata); /** * Release the crypto if applicable. */ media_status_t AMediaCodec_releaseCrypto(AMediaCodec*); /** * Call this after AMediaCodec_configure() returns successfully to get the input * format accepted by the codec. Do this to determine what optional configuration * parameters were supported by the codec. */ AMediaFormat* AMediaCodec_getInputFormat(AMediaCodec*); /** * Returns true if the codec cannot proceed further, but can be recovered by stopping, * configuring, and starting again. */ bool AMediaCodecActionCode_isRecoverable(int32_t actionCode); /** * Returns true if the codec error is a transient issue, perhaps due to * resource constraints, and that the method (or encoding/decoding) may be * retried at a later time. */ bool AMediaCodecActionCode_isTransient(int32_t actionCode); #endif /* __ANDROID_API__ >= 28 */ typedef enum { AMEDIACODECRYPTOINFO_MODE_CLEAR = 0, AMEDIACODECRYPTOINFO_MODE_AES_CTR = 1, Loading media/ndk/include/media/NdkMediaError.h +11 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,17 @@ __BEGIN_DECLS typedef enum { AMEDIA_OK = 0, /** * This indicates required resource was not able to be allocated. */ AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE = 1100, /** * This indicates the resource manager reclaimed the media resource used by the codec. * With this error, the codec must be released, as it has moved to terminal state. */ AMEDIACODEC_ERROR_RECLAIMED = 1101, AMEDIA_ERROR_BASE = -10000, AMEDIA_ERROR_UNKNOWN = AMEDIA_ERROR_BASE, AMEDIA_ERROR_MALFORMED = AMEDIA_ERROR_BASE - 1, Loading media/ndk/include/media/NdkMediaFormat.h +44 −1 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
media/ndk/NdkMediaCodec.cpp +254 −3 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ static media_status_t translate_error(status_t err) { enum { kWhatActivityNotify, kWhatAsyncNotify, kWhatRequestActivityNotifications, kWhatStopActivityNotifications, }; Loading Loading @@ -88,6 +89,11 @@ struct AMediaCodec { bool mRequestedActivityNotification; OnCodecEvent mCallback; void *mCallbackUserData; sp<AMessage> mAsyncNotify; mutable Mutex mAsyncCallbackLock; AMediaCodecOnAsyncNotifyCallback mAsyncCallback; void *mAsyncCallbackUserData; }; CodecHandler::CodecHandler(AMediaCodec *codec) { Loading Loading @@ -128,6 +134,147 @@ void CodecHandler::onMessageReceived(const sp<AMessage> &msg) { break; } case kWhatAsyncNotify: { int32_t cbID; if (!msg->findInt32("callbackID", &cbID)) { ALOGE("kWhatAsyncNotify: callbackID is expected."); break; } ALOGV("kWhatAsyncNotify: cbID = %d", cbID); switch (cbID) { case MediaCodec::CB_INPUT_AVAILABLE: { int32_t index; if (!msg->findInt32("index", &index)) { ALOGE("CB_INPUT_AVAILABLE: index is expected."); break; } Mutex::Autolock _l(mCodec->mAsyncCallbackLock); if (mCodec->mAsyncCallbackUserData != NULL || mCodec->mAsyncCallback.onAsyncInputAvailable != NULL) { mCodec->mAsyncCallback.onAsyncInputAvailable( mCodec, mCodec->mAsyncCallbackUserData, index); } break; } case MediaCodec::CB_OUTPUT_AVAILABLE: { int32_t index; size_t offset; size_t size; int64_t timeUs; int32_t flags; if (!msg->findInt32("index", &index)) { ALOGE("CB_OUTPUT_AVAILABLE: index is expected."); break; } if (!msg->findSize("offset", &offset)) { ALOGE("CB_OUTPUT_AVAILABLE: offset is expected."); break; } if (!msg->findSize("size", &size)) { ALOGE("CB_OUTPUT_AVAILABLE: size is expected."); break; } if (!msg->findInt64("timeUs", &timeUs)) { ALOGE("CB_OUTPUT_AVAILABLE: timeUs is expected."); break; } if (!msg->findInt32("flags", &flags)) { ALOGE("CB_OUTPUT_AVAILABLE: flags is expected."); break; } AMediaCodecBufferInfo bufferInfo = { (int32_t)offset, (int32_t)size, timeUs, (uint32_t)flags}; Mutex::Autolock _l(mCodec->mAsyncCallbackLock); if (mCodec->mAsyncCallbackUserData != NULL || mCodec->mAsyncCallback.onAsyncOutputAvailable != NULL) { mCodec->mAsyncCallback.onAsyncOutputAvailable( mCodec, mCodec->mAsyncCallbackUserData, index, &bufferInfo); } break; } case MediaCodec::CB_OUTPUT_FORMAT_CHANGED: { sp<AMessage> format; if (!msg->findMessage("format", &format)) { ALOGE("CB_OUTPUT_FORMAT_CHANGED: format is expected."); break; } AMediaFormat *aMediaFormat = AMediaFormat_fromMsg(&format); Mutex::Autolock _l(mCodec->mAsyncCallbackLock); if (mCodec->mAsyncCallbackUserData != NULL || mCodec->mAsyncCallback.onAsyncFormatChanged != NULL) { mCodec->mAsyncCallback.onAsyncFormatChanged( mCodec, mCodec->mAsyncCallbackUserData, aMediaFormat); } break; } case MediaCodec::CB_ERROR: { status_t err; int32_t actionCode; AString detail; if (!msg->findInt32("err", &err)) { ALOGE("CB_ERROR: err is expected."); break; } if (!msg->findInt32("action", &actionCode)) { ALOGE("CB_ERROR: action is expected."); break; } msg->findString("detail", &detail); ALOGE("Decoder reported error(0x%x), actionCode(%d), detail(%s)", err, actionCode, detail.c_str()); Mutex::Autolock _l(mCodec->mAsyncCallbackLock); if (mCodec->mAsyncCallbackUserData != NULL || mCodec->mAsyncCallback.onAsyncError != NULL) { mCodec->mAsyncCallback.onAsyncError( mCodec, mCodec->mAsyncCallbackUserData, translate_error(err), actionCode, detail.c_str()); } break; } default: { ALOGE("kWhatAsyncNotify: callbackID(%d) is unexpected.", cbID); break; } } break; } case kWhatStopActivityNotifications: { sp<AReplyToken> replyID; Loading Loading @@ -162,7 +309,7 @@ static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool size_t res = mData->mLooper->start( false, // runOnCallingThread true, // canCallJava XXX PRIORITY_FOREGROUND); PRIORITY_AUDIO); if (res != OK) { ALOGE("Failed to start the looper"); AMediaCodec_delete(mData); Loading @@ -183,6 +330,9 @@ static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool mData->mRequestedActivityNotification = false; mData->mCallback = NULL; mData->mAsyncCallback = {}; mData->mAsyncCallbackUserData = NULL; return mData; } Loading Loading @@ -221,6 +371,32 @@ media_status_t AMediaCodec_delete(AMediaCodec *mData) { return AMEDIA_OK; } EXPORT media_status_t AMediaCodec_getName( AMediaCodec *mData, char** out_name) { if (out_name == NULL) { return AMEDIA_ERROR_INVALID_PARAMETER; } AString compName; status_t err = mData->mCodec->getName(&compName); if (err != OK) { return translate_error(err); } *out_name = strdup(compName.c_str()); return AMEDIA_OK; } EXPORT void AMediaCodec_releaseName( AMediaCodec * /* mData */, char* name) { if (name != NULL) { free(name); } } EXPORT media_status_t AMediaCodec_configure( AMediaCodec *mData, Loading @@ -236,8 +412,40 @@ media_status_t AMediaCodec_configure( surface = (Surface*) window; } return translate_error(mData->mCodec->configure(nativeFormat, surface, crypto ? crypto->mCrypto : NULL, flags)); status_t err = mData->mCodec->configure(nativeFormat, surface, crypto ? crypto->mCrypto : NULL, flags); if (err != OK) { ALOGE("configure: err(%d), failed with format: %s", err, nativeFormat->debugString(0).c_str()); } return translate_error(err); } EXPORT media_status_t AMediaCodec_setAsyncNotifyCallback( AMediaCodec *mData, AMediaCodecOnAsyncNotifyCallback callback, void *userdata) { if (mData->mAsyncNotify == NULL && userdata != NULL) { mData->mAsyncNotify = new AMessage(kWhatAsyncNotify, mData->mHandler); status_t err = mData->mCodec->setCallback(mData->mAsyncNotify); if (err != OK) { ALOGE("setAsyncNotifyCallback: err(%d), failed to set async callback", err); return translate_error(err); } } Mutex::Autolock _l(mData->mAsyncCallbackLock); mData->mAsyncCallback = callback; mData->mAsyncCallbackUserData = userdata; return AMEDIA_OK; } EXPORT media_status_t AMediaCodec_releaseCrypto(AMediaCodec *mData) { return translate_error(mData->mCodec->releaseCrypto()); } EXPORT Loading Loading @@ -282,6 +490,19 @@ ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) { EXPORT uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) { if (mData->mAsyncNotify != NULL) { // Asynchronous mode sp<MediaCodecBuffer> abuf; if (mData->mCodec->getInputBuffer(idx, &abuf) != 0) { return NULL; } if (out_size != NULL) { *out_size = abuf->capacity(); } return abuf->data(); } android::Vector<android::sp<android::MediaCodecBuffer> > abufs; if (mData->mCodec->getInputBuffers(&abufs) == 0) { size_t n = abufs.size(); Loading @@ -304,6 +525,19 @@ uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_ EXPORT uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) { if (mData->mAsyncNotify != NULL) { // Asynchronous mode sp<MediaCodecBuffer> abuf; if (mData->mCodec->getOutputBuffer(idx, &abuf) != 0) { return NULL; } if (out_size != NULL) { *out_size = abuf->capacity(); } return abuf->data(); } android::Vector<android::sp<android::MediaCodecBuffer> > abufs; if (mData->mCodec->getOutputBuffers(&abufs) == 0) { size_t n = abufs.size(); Loading Loading @@ -366,6 +600,13 @@ AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) { return AMediaFormat_fromMsg(&format); } EXPORT AMediaFormat* AMediaCodec_getInputFormat(AMediaCodec *mData) { sp<AMessage> format; mData->mCodec->getInputFormat(&format); return AMediaFormat_fromMsg(&format); } EXPORT AMediaFormat* AMediaCodec_getBufferFormat(AMediaCodec *mData, size_t index) { sp<AMessage> format; Loading Loading @@ -542,6 +783,16 @@ media_status_t AMediaCodec_queueSecureInputBuffer( return translate_error(err); } EXPORT bool AMediaCodecActionCode_isRecoverable(int32_t actionCode) { return (actionCode == ACTION_CODE_RECOVERABLE); } EXPORT bool AMediaCodecActionCode_isTransient(int32_t actionCode) { return (actionCode == ACTION_CODE_TRANSIENT); } EXPORT void AMediaCodecCryptoInfo_setPattern(AMediaCodecCryptoInfo *info, Loading
media/ndk/NdkMediaFormat.cpp +67 −1 Original line number Diff line number Diff line Loading @@ -125,6 +125,14 @@ const char* AMediaFormat_toString(AMediaFormat *mData) { ret.appendFormat("double(%f)", val); break; } case AMessage::kTypeRect: { int32_t left, top, right, bottom; f->findRect(name, &left, &top, &right, &bottom); ret.appendFormat("Rect(%" PRId32 ", %" PRId32 ", %" PRId32 ", %" PRId32 ")", left, top, right, bottom); break; } case AMessage::kTypeString: { AString val; Loading Loading @@ -164,11 +172,22 @@ bool AMediaFormat_getFloat(AMediaFormat* format, const char *name, float *out) { return format->mFormat->findFloat(name, out); } EXPORT bool AMediaFormat_getDouble(AMediaFormat* format, const char *name, double *out) { return format->mFormat->findDouble(name, out); } EXPORT bool AMediaFormat_getSize(AMediaFormat* format, const char *name, size_t *out) { return format->mFormat->findSize(name, out); } EXPORT bool AMediaFormat_getRect(AMediaFormat* format, const char *name, int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) { return format->mFormat->findRect(name, left, top, right, bottom); } EXPORT bool AMediaFormat_getBuffer(AMediaFormat* format, const char *name, void** data, size_t *outsize) { sp<ABuffer> buf; Loading Loading @@ -215,6 +234,22 @@ void AMediaFormat_setFloat(AMediaFormat* format, const char* name, float value) format->mFormat->setFloat(name, value); } EXPORT void AMediaFormat_setDouble(AMediaFormat* format, const char* name, double value) { format->mFormat->setDouble(name, value); } EXPORT void AMediaFormat_setSize(AMediaFormat* format, const char* name, size_t value) { format->mFormat->setSize(name, value); } EXPORT void AMediaFormat_setRect(AMediaFormat* format, const char *name, int32_t left, int32_t top, int32_t right, int32_t bottom) { format->mFormat->setRect(name, left, top, right, bottom); } EXPORT void AMediaFormat_setString(AMediaFormat* format, const char* name, const char* value) { // AMessage::setString() makes a copy of the string Loading @@ -233,30 +268,61 @@ void AMediaFormat_setBuffer(AMediaFormat* format, const char* name, void* data, } EXPORT const char* AMEDIAFORMAT_KEY_AAC_DRC_ATTENUATION_FACTOR = "aac-drc-cut-level"; EXPORT const char* AMEDIAFORMAT_KEY_AAC_DRC_BOOST_FACTOR = "aac-drc-boost-level"; EXPORT const char* AMEDIAFORMAT_KEY_AAC_DRC_HEAVY_COMPRESSION = "aac-drc-heavy-compression"; EXPORT const char* AMEDIAFORMAT_KEY_AAC_DRC_TARGET_REFERENCE_LEVEL = "aac-target-ref-level"; EXPORT const char* AMEDIAFORMAT_KEY_AAC_ENCODED_TARGET_LEVEL = "aac-encoded-target-level"; EXPORT const char* AMEDIAFORMAT_KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count"; EXPORT const char* AMEDIAFORMAT_KEY_AAC_PROFILE = "aac-profile"; EXPORT const char* AMEDIAFORMAT_KEY_AAC_SBR_MODE = "aac-sbr-mode"; EXPORT const char* AMEDIAFORMAT_KEY_AUDIO_SESSION_ID = "audio-session-id"; EXPORT const char* AMEDIAFORMAT_KEY_BITRATE_MODE = "bitrate-mode"; EXPORT const char* AMEDIAFORMAT_KEY_BIT_RATE = "bitrate"; EXPORT const char* AMEDIAFORMAT_KEY_CAPTURE_RATE = "capture-rate"; EXPORT const char* AMEDIAFORMAT_KEY_CHANNEL_COUNT = "channel-count"; EXPORT const char* AMEDIAFORMAT_KEY_CHANNEL_MASK = "channel-mask"; EXPORT const char* AMEDIAFORMAT_KEY_COLOR_FORMAT = "color-format"; EXPORT const char* AMEDIAFORMAT_KEY_COLOR_RANGE = "color-range"; EXPORT const char* AMEDIAFORMAT_KEY_COLOR_STANDARD = "color-standard"; EXPORT const char* AMEDIAFORMAT_KEY_COLOR_TRANSFER = "color-transfer"; EXPORT const char* AMEDIAFORMAT_KEY_COMPLEXITY = "complexity"; EXPORT const char* AMEDIAFORMAT_KEY_DISPLAY_CROP = "crop"; EXPORT const char* AMEDIAFORMAT_KEY_DURATION = "durationUs"; EXPORT const char* AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level"; EXPORT const char* AMEDIAFORMAT_KEY_FRAME_RATE = "frame-rate"; EXPORT const char* AMEDIAFORMAT_KEY_GRID_COLS = "grid-cols"; EXPORT const char* AMEDIAFORMAT_KEY_GRID_HEIGHT = "grid-height"; EXPORT const char* AMEDIAFORMAT_KEY_GRID_ROWS = "grid-rows"; EXPORT const char* AMEDIAFORMAT_KEY_GRID_WIDTH = "grid-width"; EXPORT const char* AMEDIAFORMAT_KEY_HDR_STATIC_INFO = "hdr-static-info"; EXPORT const char* AMEDIAFORMAT_KEY_HEIGHT = "height"; EXPORT const char* AMEDIAFORMAT_KEY_INTRA_REFRESH_PERIOD = "intra-refresh-period"; EXPORT const char* AMEDIAFORMAT_KEY_IS_ADTS = "is-adts"; EXPORT const char* AMEDIAFORMAT_KEY_IS_AUTOSELECT = "is-autoselect"; EXPORT const char* AMEDIAFORMAT_KEY_IS_DEFAULT = "is-default"; EXPORT const char* AMEDIAFORMAT_KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle"; EXPORT const char* AMEDIAFORMAT_KEY_I_FRAME_INTERVAL = "i-frame-interval"; EXPORT const char* AMEDIAFORMAT_KEY_LANGUAGE = "language"; EXPORT const char* AMEDIAFORMAT_KEY_LATENCY = "latency"; EXPORT const char* AMEDIAFORMAT_KEY_LEVEL = "level"; EXPORT const char* AMEDIAFORMAT_KEY_MAX_HEIGHT = "max-height"; EXPORT const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE = "max-input-size"; EXPORT const char* AMEDIAFORMAT_KEY_MAX_WIDTH = "max-width"; EXPORT const char* AMEDIAFORMAT_KEY_MIME = "mime"; EXPORT const char* AMEDIAFORMAT_KEY_OPERATING_RATE = "operating-rate"; EXPORT const char* AMEDIAFORMAT_KEY_PCM_ENCODING = "pcm-encoding"; EXPORT const char* AMEDIAFORMAT_KEY_PRIORITY = "priority"; EXPORT const char* AMEDIAFORMAT_KEY_PROFILE = "profile"; EXPORT const char* AMEDIAFORMAT_KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown"; EXPORT const char* AMEDIAFORMAT_KEY_REPEAT_PREVIOUS_FRAME_AFTER = "repeat-previous-frame-after"; EXPORT const char* AMEDIAFORMAT_KEY_ROTATION = "rotation-degrees"; EXPORT const char* AMEDIAFORMAT_KEY_SAMPLE_RATE = "sample-rate"; EXPORT const char* AMEDIAFORMAT_KEY_WIDTH = "width"; EXPORT const char* AMEDIAFORMAT_KEY_SLICE_HEIGHT = "slice-height"; EXPORT const char* AMEDIAFORMAT_KEY_STRIDE = "stride"; EXPORT const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYERING = "ts-schema"; EXPORT const char* AMEDIAFORMAT_KEY_TRACK_ID = "track-id"; EXPORT const char* AMEDIAFORMAT_KEY_WIDTH = "width"; } // extern "C" Loading
media/ndk/include/media/NdkMediaCodec.h +118 −1 Original line number Diff line number Diff line Loading @@ -53,11 +53,63 @@ typedef struct AMediaCodecBufferInfo AMediaCodecBufferInfo; typedef struct AMediaCodecCryptoInfo AMediaCodecCryptoInfo; enum { AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG = 2, AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM = 4, AMEDIACODEC_BUFFER_FLAG_PARTIAL_FRAME = 8, AMEDIACODEC_CONFIGURE_FLAG_ENCODE = 1, AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED = -3, AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED = -2, AMEDIACODEC_INFO_TRY_AGAIN_LATER = -1 AMEDIACODEC_INFO_TRY_AGAIN_LATER = -1, }; /** * Called when an input buffer becomes available. * The specified index is the index of the available input buffer. */ typedef void (*AMediaCodecOnAsyncInputAvailable)( AMediaCodec *codec, void *userdata, int32_t index); /** * Called when an output buffer becomes available. * The specified index is the index of the available output buffer. * The specified bufferInfo contains information regarding the available output buffer. */ typedef void (*AMediaCodecOnAsyncOutputAvailable)( AMediaCodec *codec, void *userdata, int32_t index, AMediaCodecBufferInfo *bufferInfo); /** * Called when the output format has changed. * The specified format contains the new output format. */ typedef void (*AMediaCodecOnAsyncFormatChanged)( AMediaCodec *codec, void *userdata, AMediaFormat *format); /** * Called when the MediaCodec encountered an error. * The specified actionCode indicates the possible actions that client can take, * and it can be checked by calling AMediaCodecActionCode_isRecoverable or * AMediaCodecActionCode_isTransient. If both AMediaCodecActionCode_isRecoverable() * and AMediaCodecActionCode_isTransient() return false, then the codec error is fatal * and the codec must be deleted. * The specified detail may contain more detailed messages about this error. */ typedef void (*AMediaCodecOnAsyncError)( AMediaCodec *codec, void *userdata, media_status_t error, int32_t actionCode, const char *detail); struct AMediaCodecOnAsyncNotifyCallback { AMediaCodecOnAsyncInputAvailable onAsyncInputAvailable; AMediaCodecOnAsyncOutputAvailable onAsyncOutputAvailable; AMediaCodecOnAsyncFormatChanged onAsyncFormatChanged; AMediaCodecOnAsyncError onAsyncError; }; #if __ANDROID_API__ >= 21 Loading Loading @@ -289,6 +341,71 @@ media_status_t AMediaCodec_signalEndOfInputStream(AMediaCodec *mData); #endif /* __ANDROID_API__ >= 26 */ #if __ANDROID_API__ >= 28 /** * Get the component name. If the codec was created by createDecoderByType * or createEncoderByType, what component is chosen is not known beforehand. * Caller shall call AMediaCodec_releaseName to free the returned pointer. */ media_status_t AMediaCodec_getName(AMediaCodec*, char** out_name); /** * Free the memory pointed by name which is returned by AMediaCodec_getName. */ void AMediaCodec_releaseName(AMediaCodec*, char* name); /** * Set an asynchronous callback for actionable AMediaCodec events. * When asynchronous callback is enabled, the client should not call * AMediaCodec_getInputBuffers(), AMediaCodec_getOutputBuffers(), * AMediaCodec_dequeueInputBuffer() or AMediaCodec_dequeueOutputBuffer(). * * Also, AMediaCodec_flush() behaves differently in asynchronous mode. * After calling AMediaCodec_flush(), you must call AMediaCodec_start() to * "resume" receiving input buffers, even if an input surface was created. * * Refer to the definition of AMediaCodecOnAsyncNotifyCallback 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_setAsyncNotifyCallback should not be called on the callback thread. * No heavy duty task should be performed on callback thread. */ media_status_t AMediaCodec_setAsyncNotifyCallback( AMediaCodec*, AMediaCodecOnAsyncNotifyCallback callback, void *userdata); /** * Release the crypto if applicable. */ media_status_t AMediaCodec_releaseCrypto(AMediaCodec*); /** * Call this after AMediaCodec_configure() returns successfully to get the input * format accepted by the codec. Do this to determine what optional configuration * parameters were supported by the codec. */ AMediaFormat* AMediaCodec_getInputFormat(AMediaCodec*); /** * Returns true if the codec cannot proceed further, but can be recovered by stopping, * configuring, and starting again. */ bool AMediaCodecActionCode_isRecoverable(int32_t actionCode); /** * Returns true if the codec error is a transient issue, perhaps due to * resource constraints, and that the method (or encoding/decoding) may be * retried at a later time. */ bool AMediaCodecActionCode_isTransient(int32_t actionCode); #endif /* __ANDROID_API__ >= 28 */ typedef enum { AMEDIACODECRYPTOINFO_MODE_CLEAR = 0, AMEDIACODECRYPTOINFO_MODE_AES_CTR = 1, Loading
media/ndk/include/media/NdkMediaError.h +11 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,17 @@ __BEGIN_DECLS typedef enum { AMEDIA_OK = 0, /** * This indicates required resource was not able to be allocated. */ AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE = 1100, /** * This indicates the resource manager reclaimed the media resource used by the codec. * With this error, the codec must be released, as it has moved to terminal state. */ AMEDIACODEC_ERROR_RECLAIMED = 1101, AMEDIA_ERROR_BASE = -10000, AMEDIA_ERROR_UNKNOWN = AMEDIA_ERROR_BASE, AMEDIA_ERROR_MALFORMED = AMEDIA_ERROR_BASE - 1, Loading
media/ndk/include/media/NdkMediaFormat.h +44 −1 File changed.Preview size limit exceeded, changes collapsed. Show changes