diff --git a/configure b/configure
index eefd103414..ee2e3ba6ac 100755
--- a/configure
+++ b/configure
@@ -3191,6 +3191,7 @@ h264_crystalhd_decoder_select="crystalhd h264_mp4toannexb_bsf h264_parser"
 h264_cuvid_decoder_deps="cuvid"
 h264_cuvid_decoder_select="h264_mp4toannexb_bsf"
 h264_mediacodec_decoder_deps="mediacodec"
+h264_mediacodec_decoder_extralibs="-landroid"
 h264_mediacodec_decoder_select="h264_mp4toannexb_bsf h264_parser"
 h264_mf_encoder_deps="mediafoundation"
 h264_mmal_decoder_deps="mmal"
@@ -3209,6 +3210,7 @@ hevc_amf_encoder_deps="amf"
 hevc_cuvid_decoder_deps="cuvid"
 hevc_cuvid_decoder_select="hevc_mp4toannexb_bsf"
 hevc_mediacodec_decoder_deps="mediacodec"
+hevc_mediacodec_decoder_extralibs="-landroid"
 hevc_mediacodec_decoder_select="hevc_mp4toannexb_bsf hevc_parser"
 hevc_mf_encoder_deps="mediafoundation"
 hevc_nvenc_encoder_deps="nvenc"
diff --git a/libavcodec/mediacodec_wrapper.c b/libavcodec/mediacodec_wrapper.c
index e0c614680e..b12aced711 100644
--- a/libavcodec/mediacodec_wrapper.c
+++ b/libavcodec/mediacodec_wrapper.c
@@ -20,7 +20,11 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include <dlfcn.h>
 #include <jni.h>
+#include <media/NdkMediaFormat.h>
+#include <media/NdkMediaCodec.h>
+#include <android/native_window_jni.h>
 
 #include "libavutil/avassert.h"
 #include "libavutil/mem.h"
@@ -1794,23 +1798,607 @@ static const FFAMediaCodec media_codec_jni = {
     .cleanOutputBuffers = mediacodec_jni_cleanOutputBuffers,
 };
 
-FFAMediaFormat *ff_AMediaFormat_new(void)
+typedef struct FFAMediaFormatNdk {
+    FFAMediaFormat api;
+
+    void *libmedia;
+    AMediaFormat *impl;
+
+    AMediaFormat *(*new)(void);
+    media_status_t (*delete)(AMediaFormat*);
+
+    const char* (*toString)(AMediaFormat*);
+
+    bool (*getInt32)(AMediaFormat*, const char *name, int32_t *out);
+    bool (*getInt64)(AMediaFormat*, const char *name, int64_t *out);
+    bool (*getFloat)(AMediaFormat*, const char *name, float *out);
+    bool (*getSize)(AMediaFormat*, const char *name, size_t *out);
+    bool (*getBuffer)(AMediaFormat*, const char *name, void** data, size_t *size);
+    bool (*getString)(AMediaFormat*, const char *name, const char **out);
+
+    void (*setInt32)(AMediaFormat*, const char* name, int32_t value);
+    void (*setInt64)(AMediaFormat*, const char* name, int64_t value);
+    void (*setFloat)(AMediaFormat*, const char* name, float value);
+    void (*setString)(AMediaFormat*, const char* name, const char* value);
+    void (*setBuffer)(AMediaFormat*, const char* name, const void* data, size_t size);
+} FFAMediaFormatNdk;
+
+typedef struct FFAMediaCodecNdk {
+    FFAMediaCodec api;
+
+    void *libmedia;
+    AMediaCodec *impl;
+    ANativeWindow *window;
+
+    AMediaCodec* (*createCodecByName)(const char *name);
+    AMediaCodec* (*createDecoderByType)(const char *mime_type);
+    AMediaCodec* (*createEncoderByType)(const char *mime_type);
+    media_status_t (*delete)(AMediaCodec*);
+
+    media_status_t (*configure)(AMediaCodec *,
+                                const AMediaFormat *format,
+                                ANativeWindow *surface,
+                                AMediaCrypto *crypto,
+                                uint32_t flags);
+    media_status_t (*start)(AMediaCodec*);
+    media_status_t (*stop)(AMediaCodec*);
+    media_status_t (*flush)(AMediaCodec*);
+
+    uint8_t* (*getInputBuffer)(AMediaCodec*, size_t idx, size_t *out_size);
+    uint8_t* (*getOutputBuffer)(AMediaCodec*, size_t idx, size_t *out_size);
+
+    ssize_t (*dequeueInputBuffer)(AMediaCodec*, int64_t timeoutUs);
+    media_status_t (*queueInputBuffer)(AMediaCodec*, size_t idx,
+                                       long offset, size_t size,
+                                       uint64_t time, uint32_t flags);
+
+    ssize_t (*dequeueOutputBuffer)(AMediaCodec*, AMediaCodecBufferInfo *info, int64_t timeoutUs);
+    AMediaFormat* (*getOutputFormat)(AMediaCodec*);
+
+    media_status_t (*releaseOutputBuffer)(AMediaCodec*, size_t idx, bool render);
+    media_status_t (*releaseOutputBufferAtTime)(AMediaCodec *mData, size_t idx, int64_t timestampNs);
+
+    // Available since API level 28.
+    media_status_t (*getName)(AMediaCodec*, char** out_name);
+    void (*releaseName)(AMediaCodec*, char* name);
+} FFAMediaCodecNdk;
+
+static const FFAMediaFormat media_format_ndk;
+static const FFAMediaCodec media_codec_ndk;
+
+static const AVClass amediaformat_ndk_class = {
+    .class_name = "amediaformat_ndk",
+    .item_name  = av_default_item_name,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+static const AVClass amediacodec_ndk_class = {
+    .class_name = "amediacodec_ndk",
+    .item_name  = av_default_item_name,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+static FFAMediaFormat *mediaformat_ndk_create(AMediaFormat *impl)
+{
+    FFAMediaFormatNdk *format = av_mallocz(sizeof(*format));
+    if (!format)
+        return NULL;
+
+    format->api = media_format_ndk;
+
+    format->libmedia = dlopen("libmediandk.so", RTLD_NOW);
+    if (!format->libmedia)
+        goto error;
+
+#define GET_SYMBOL(sym) \
+    format->sym = dlsym(format->libmedia, "AMediaFormat_" #sym);    \
+    if (!format->sym)                                               \
+        goto error;
+
+    GET_SYMBOL(new)
+    GET_SYMBOL(delete)
+
+    GET_SYMBOL(toString)
+
+    GET_SYMBOL(getInt32)
+    GET_SYMBOL(getInt64)
+    GET_SYMBOL(getFloat)
+    GET_SYMBOL(getSize)
+    GET_SYMBOL(getBuffer)
+    GET_SYMBOL(getString)
+
+    GET_SYMBOL(setInt32)
+    GET_SYMBOL(setInt64)
+    GET_SYMBOL(setFloat)
+    GET_SYMBOL(setString)
+    GET_SYMBOL(setBuffer)
+
+#undef GET_SYMBOL
+
+    if (impl) {
+        format->impl = impl;
+    } else {
+        format->impl = format->new();
+        if (!format->impl)
+            goto error;
+    }
+
+    return (FFAMediaFormat *)format;
+
+error:
+    if (format->libmedia)
+        dlclose(format->libmedia);
+    av_freep(&format);
+    return NULL;
+}
+
+static FFAMediaFormat *mediaformat_ndk_new(void)
+{
+    return mediaformat_ndk_create(NULL);
+}
+
+static int mediaformat_ndk_delete(FFAMediaFormat* ctx)
+{
+    FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
+    int ret = 0;
+    if (!format)
+        return 0;
+
+    av_assert0(format->api.class == &amediaformat_ndk_class);
+
+    if (format->impl && (format->delete(format->impl) != AMEDIA_OK))
+            ret = AVERROR_EXTERNAL;
+    if (format->libmedia)
+        dlclose(format->libmedia);
+    av_free(format);
+
+    return ret;
+}
+
+static char* mediaformat_ndk_toString(FFAMediaFormat* ctx)
+{
+    FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
+    const char *str = format->toString(format->impl);
+    return av_strdup(str);
+}
+
+static int mediaformat_ndk_getInt32(FFAMediaFormat* ctx, const char *name, int32_t *out)
+{
+    FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
+    return format->getInt32(format->impl, name, out);
+}
+
+static int mediaformat_ndk_getInt64(FFAMediaFormat* ctx, const char *name, int64_t *out)
+{
+    FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
+    return format->getInt64(format->impl, name, out);
+}
+
+static int mediaformat_ndk_getFloat(FFAMediaFormat* ctx, const char *name, float *out)
+{
+    FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
+    return format->getFloat(format->impl, name, out);
+}
+
+static int mediaformat_ndk_getBuffer(FFAMediaFormat* ctx, const char *name, void** data, size_t *size)
+{
+    FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
+    return format->getBuffer(format->impl, name, data, size);
+}
+
+static int mediaformat_ndk_getString(FFAMediaFormat* ctx, const char *name, const char **out)
+{
+    FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
+    const char *tmp = NULL;
+    int ret = format->getString(format->impl, name, &tmp);
+
+    if (tmp)
+        *out = av_strdup(tmp);
+    return ret;
+}
+
+static void mediaformat_ndk_setInt32(FFAMediaFormat* ctx, const char* name, int32_t value)
+{
+    FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
+    format->setInt32(format->impl, name, value);
+}
+
+static void mediaformat_ndk_setInt64(FFAMediaFormat* ctx, const char* name, int64_t value)
+{
+    FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
+    format->setInt64(format->impl, name, value);
+}
+
+static void mediaformat_ndk_setFloat(FFAMediaFormat* ctx, const char* name, float value)
+{
+    FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
+    format->setFloat(format->impl, name, value);
+}
+
+static void mediaformat_ndk_setString(FFAMediaFormat* ctx, const char* name, const char* value)
+{
+    FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
+    format->setString(format->impl, name, value);
+}
+
+static void mediaformat_ndk_setBuffer(FFAMediaFormat* ctx, const char* name, void* data, size_t size)
+{
+    FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)ctx;
+    format->setBuffer(format->impl, name, data, size);
+}
+
+static char *mediacodec_ndk_getName(FFAMediaCodec *ctx)
+{
+    FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
+    char *ret = NULL;
+    char *name = NULL;
+
+    if (!codec->getName || !codec->releaseName) {
+        av_log(ctx, AV_LOG_DEBUG, "getName() unavailable\n");
+        return ret;
+    }
+
+    codec->getName(codec->impl, &name);
+    if (name) {
+        ret = av_strdup(name);
+        codec->releaseName(codec->impl, name);
+    }
+
+    return ret;
+}
+
+static inline FFAMediaCodec *ndk_codec_create(int method, const char *arg) {
+    FFAMediaCodecNdk *codec = av_mallocz(sizeof(*codec));
+    const char *lib_name = "libmediandk.so";
+
+    if (!codec)
+        return NULL;
+
+    codec->api = media_codec_ndk;
+    codec->libmedia = dlopen(lib_name, RTLD_NOW);
+    if (!codec->libmedia)
+        goto error;
+
+#define GET_SYMBOL(sym, required)                                   \
+    codec->sym = dlsym(codec->libmedia, "AMediaCodec_" #sym);       \
+    if (!codec->sym) {                                              \
+        av_log(codec, required ? AV_LOG_ERROR : AV_LOG_INFO,        \
+               #sym "() unavailable from %s\n", lib_name);          \
+        if (required)                                               \
+            goto error;                                             \
+    }
+
+    GET_SYMBOL(createCodecByName, 1)
+    GET_SYMBOL(createDecoderByType, 1)
+    GET_SYMBOL(createEncoderByType, 1)
+    GET_SYMBOL(delete, 1)
+
+    GET_SYMBOL(configure, 1)
+    GET_SYMBOL(start, 1)
+    GET_SYMBOL(stop, 1)
+    GET_SYMBOL(flush, 1)
+
+    GET_SYMBOL(getInputBuffer, 1)
+    GET_SYMBOL(getOutputBuffer, 1)
+
+    GET_SYMBOL(dequeueInputBuffer, 1)
+    GET_SYMBOL(queueInputBuffer, 1)
+
+    GET_SYMBOL(dequeueOutputBuffer, 1)
+    GET_SYMBOL(getOutputFormat, 1)
+
+    GET_SYMBOL(releaseOutputBuffer, 1)
+    GET_SYMBOL(releaseOutputBufferAtTime, 1)
+
+    GET_SYMBOL(getName, 0)
+    GET_SYMBOL(releaseName, 0)
+
+#undef GET_SYMBOL
+
+    switch (method) {
+    case CREATE_CODEC_BY_NAME:
+        codec->impl = codec->createCodecByName(arg);
+        break;
+    case CREATE_DECODER_BY_TYPE:
+        codec->impl = codec->createDecoderByType(arg);
+        break;
+    case CREATE_ENCODER_BY_TYPE:
+        codec->impl = codec->createEncoderByType(arg);
+        break;
+    default:
+        av_assert0(0);
+    }
+    if (!codec->impl)
+        goto error;
+
+    return (FFAMediaCodec *)codec;
+
+error:
+    if (codec->libmedia)
+        dlclose(codec->libmedia);
+    av_freep(&codec);
+    return NULL;
+}
+
+#define DECLARE_NDK_AMEDIACODEC_CREATE_FUNC(name, method)       \
+static FFAMediaCodec *mediacodec_ndk_##name(const char *arg)    \
+{                                                               \
+    return ndk_codec_create(method, arg);                       \
+}                                                               \
+
+DECLARE_NDK_AMEDIACODEC_CREATE_FUNC(createCodecByName,   CREATE_CODEC_BY_NAME)
+DECLARE_NDK_AMEDIACODEC_CREATE_FUNC(createDecoderByType, CREATE_DECODER_BY_TYPE)
+DECLARE_NDK_AMEDIACODEC_CREATE_FUNC(createEncoderByType, CREATE_ENCODER_BY_TYPE)
+
+static int mediacodec_ndk_delete(FFAMediaCodec* ctx)
+{
+    FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
+    int ret = 0;
+
+    if (!codec)
+        return 0;
+
+    av_assert0(codec->api.class == &amediacodec_ndk_class);
+
+    if (codec->impl && (codec->delete(codec->impl) != AMEDIA_OK))
+        ret = AVERROR_EXTERNAL;
+    if (codec->window)
+        ANativeWindow_release(codec->window);
+    if (codec->libmedia)
+        dlclose(codec->libmedia);
+    av_free(codec);
+
+    return ret;
+}
+
+static int mediacodec_ndk_configure(FFAMediaCodec* ctx, const FFAMediaFormat* format_ctx, void* surface, void *crypto, uint32_t flags)
+{
+    FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
+    FFAMediaFormatNdk *format = (FFAMediaFormatNdk *)format_ctx;
+    media_status_t status;
+
+    if (surface) {
+        JNIEnv *env = NULL;
+        JNI_GET_ENV_OR_RETURN(env, ctx, -1);
+        codec->window = ANativeWindow_fromSurface(env, surface);
+    }
+
+    if (format_ctx->class != &amediaformat_ndk_class) {
+        av_log(ctx, AV_LOG_ERROR, "invalid media format\n");
+        return AVERROR(EINVAL);
+    }
+
+    status = codec->configure(codec->impl, format->impl, codec->window, NULL, flags);
+    if (status != AMEDIA_OK) {
+        av_log(codec, AV_LOG_ERROR, "configure failed, %d\n", status);
+        return AVERROR_EXTERNAL;
+    }
+
+    return 0;
+}
+
+#define MEDIACODEC_NDK_WRAPPER(method)                                   \
+static int mediacodec_ndk_ ## method(FFAMediaCodec* ctx)                 \
+{                                                                        \
+    FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;                   \
+    media_status_t status = codec->method(codec->impl);                  \
+                                                                         \
+    if (status != AMEDIA_OK) {                                           \
+        av_log(codec, AV_LOG_ERROR, #method " failed, %d\n", status);    \
+        return AVERROR_EXTERNAL;                                         \
+    }                                                                    \
+                                                                         \
+    return 0;                                                            \
+}                                                                        \
+
+MEDIACODEC_NDK_WRAPPER(start)
+MEDIACODEC_NDK_WRAPPER(stop)
+MEDIACODEC_NDK_WRAPPER(flush)
+
+static uint8_t* mediacodec_ndk_getInputBuffer(FFAMediaCodec* ctx, size_t idx, size_t *out_size)
+{
+    FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
+    return codec->getInputBuffer(codec->impl, idx, out_size);
+}
+
+static uint8_t* mediacodec_ndk_getOutputBuffer(FFAMediaCodec* ctx, size_t idx, size_t *out_size)
+{
+    FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
+    return codec->getOutputBuffer(codec->impl, idx, out_size);
+}
+
+static ssize_t mediacodec_ndk_dequeueInputBuffer(FFAMediaCodec* ctx, int64_t timeoutUs)
+{
+    FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
+    return codec->dequeueInputBuffer(codec->impl, timeoutUs);
+}
+
+static int mediacodec_ndk_queueInputBuffer(FFAMediaCodec *ctx, size_t idx,
+                                           off_t offset, size_t size,
+                                           uint64_t time, uint32_t flags)
+{
+    FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
+    return codec->queueInputBuffer(codec->impl, idx, offset, size, time, flags);
+}
+
+static ssize_t mediacodec_ndk_dequeueOutputBuffer(FFAMediaCodec* ctx, FFAMediaCodecBufferInfo *info, int64_t timeoutUs)
+{
+    FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
+    AMediaCodecBufferInfo buf_info = {0};
+    ssize_t ret;
+
+    ret = codec->dequeueOutputBuffer(codec->impl, &buf_info, timeoutUs);
+    info->offset = buf_info.offset;
+    info->size = buf_info.size;
+    info->presentationTimeUs = buf_info.presentationTimeUs;
+    info->flags = buf_info.flags;
+
+    return ret;
+}
+
+static FFAMediaFormat* mediacodec_ndk_getOutputFormat(FFAMediaCodec* ctx)
+{
+    FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
+    AMediaFormat *format = codec->getOutputFormat(codec->impl);
+
+    if (!format)
+        return NULL;
+    return mediaformat_ndk_create(format);
+}
+
+static int mediacodec_ndk_releaseOutputBuffer(FFAMediaCodec* ctx, size_t idx, int render)
+{
+    FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
+    media_status_t status;
+
+    status = codec->releaseOutputBuffer(codec->impl, idx, render);
+    if (status != AMEDIA_OK) {
+        av_log(codec, AV_LOG_ERROR, "release output buffer failed, %d\n", status);
+        return AVERROR_EXTERNAL;
+    }
+
+    return 0;
+}
+
+static int mediacodec_ndk_releaseOutputBufferAtTime(FFAMediaCodec *ctx, size_t idx, int64_t timestampNs)
+{
+    FFAMediaCodecNdk *codec = (FFAMediaCodecNdk *)ctx;
+    media_status_t status;
+
+    status = codec->releaseOutputBufferAtTime(codec->impl, idx, timestampNs);
+    if (status != AMEDIA_OK) {
+        av_log(codec, AV_LOG_ERROR, "releaseOutputBufferAtTime failed, %d\n", status);
+        return AVERROR_EXTERNAL;
+    }
+
+    return 0;
+}
+
+static int mediacodec_ndk_infoTryAgainLater(FFAMediaCodec *ctx, ssize_t idx)
+{
+    return idx == AMEDIACODEC_INFO_TRY_AGAIN_LATER;
+}
+
+static int mediacodec_ndk_infoOutputBuffersChanged(FFAMediaCodec *ctx, ssize_t idx)
+{
+    return idx == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED;
+}
+
+static int mediacodec_ndk_infoOutputFormatChanged(FFAMediaCodec *ctx, ssize_t idx)
+{
+    return idx == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED;
+}
+
+static int mediacodec_ndk_getBufferFlagCodecConfig(FFAMediaCodec *ctx)
+{
+    return AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG;
+}
+
+static int mediacodec_ndk_getBufferFlagEndOfStream(FFAMediaCodec *ctx)
+{
+    return AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
+}
+
+static int mediacodec_ndk_getBufferFlagKeyFrame(FFAMediaCodec *ctx)
+{
+    return 1;
+}
+
+static int mediacodec_ndk_getConfigureFlagEncode(FFAMediaCodec *ctx)
+{
+    return AMEDIACODEC_CONFIGURE_FLAG_ENCODE;
+}
+
+static int mediacodec_ndk_cleanOutputBuffers(FFAMediaCodec *ctx)
+{
+    return 0;
+}
+
+static const FFAMediaFormat media_format_ndk = {
+    .class = &amediaformat_ndk_class,
+
+    .create = mediaformat_ndk_new,
+    .delete = mediaformat_ndk_delete,
+
+    .toString = mediaformat_ndk_toString,
+
+    .getInt32 = mediaformat_ndk_getInt32,
+    .getInt64 = mediaformat_ndk_getInt64,
+    .getFloat = mediaformat_ndk_getFloat,
+    .getBuffer = mediaformat_ndk_getBuffer,
+    .getString = mediaformat_ndk_getString,
+
+    .setInt32 = mediaformat_ndk_setInt32,
+    .setInt64 = mediaformat_ndk_setInt64,
+    .setFloat = mediaformat_ndk_setFloat,
+    .setString = mediaformat_ndk_setString,
+    .setBuffer = mediaformat_ndk_setBuffer,
+};
+
+static const FFAMediaCodec media_codec_ndk = {
+    .class = &amediacodec_ndk_class,
+
+    .getName = mediacodec_ndk_getName,
+
+    .createCodecByName = mediacodec_ndk_createCodecByName,
+    .createDecoderByType = mediacodec_ndk_createDecoderByType,
+    .createEncoderByType = mediacodec_ndk_createEncoderByType,
+    .delete = mediacodec_ndk_delete,
+
+    .configure = mediacodec_ndk_configure,
+    .start = mediacodec_ndk_start,
+    .stop = mediacodec_ndk_stop,
+    .flush = mediacodec_ndk_flush,
+
+    .getInputBuffer = mediacodec_ndk_getInputBuffer,
+    .getOutputBuffer = mediacodec_ndk_getOutputBuffer,
+
+    .dequeueInputBuffer = mediacodec_ndk_dequeueInputBuffer,
+    .queueInputBuffer = mediacodec_ndk_queueInputBuffer,
+
+    .dequeueOutputBuffer = mediacodec_ndk_dequeueOutputBuffer,
+    .getOutputFormat = mediacodec_ndk_getOutputFormat,
+
+    .releaseOutputBuffer = mediacodec_ndk_releaseOutputBuffer,
+    .releaseOutputBufferAtTime = mediacodec_ndk_releaseOutputBufferAtTime,
+
+    .infoTryAgainLater = mediacodec_ndk_infoTryAgainLater,
+    .infoOutputBuffersChanged = mediacodec_ndk_infoOutputBuffersChanged,
+    .infoOutputFormatChanged = mediacodec_ndk_infoOutputFormatChanged,
+
+    .getBufferFlagCodecConfig = mediacodec_ndk_getBufferFlagCodecConfig,
+    .getBufferFlagEndOfStream = mediacodec_ndk_getBufferFlagEndOfStream,
+    .getBufferFlagKeyFrame = mediacodec_ndk_getBufferFlagKeyFrame,
+
+    .getConfigureFlagEncode = mediacodec_ndk_getConfigureFlagEncode,
+    .cleanOutputBuffers = mediacodec_ndk_cleanOutputBuffers,
+};
+
+FFAMediaFormat *ff_AMediaFormat_new(int ndk)
 {
+    if (ndk)
+        return media_format_ndk.create();
     return media_format_jni.create();
 }
 
-FFAMediaCodec* ff_AMediaCodec_createCodecByName(const char *name)
+FFAMediaCodec* ff_AMediaCodec_createCodecByName(const char *name, int ndk)
 {
+    if (ndk)
+        return media_codec_ndk.createCodecByName(name);
     return media_codec_jni.createCodecByName(name);
 }
 
-FFAMediaCodec* ff_AMediaCodec_createDecoderByType(const char *mime_type)
+FFAMediaCodec* ff_AMediaCodec_createDecoderByType(const char *mime_type, int ndk)
 {
+   if (ndk)
+        return media_codec_ndk.createDecoderByType(mime_type);
     return media_codec_jni.createDecoderByType(mime_type);
 }
 
-FFAMediaCodec* ff_AMediaCodec_createEncoderByType(const char *mime_type)
+FFAMediaCodec* ff_AMediaCodec_createEncoderByType(const char *mime_type, int ndk)
 {
+    if (ndk)
+        return media_codec_ndk.createEncoderByType(mime_type);
     return media_codec_jni.createEncoderByType(mime_type);
 }
 
diff --git a/libavcodec/mediacodec_wrapper.h b/libavcodec/mediacodec_wrapper.h
index 606fdbede5..b9b882f243 100644
--- a/libavcodec/mediacodec_wrapper.h
+++ b/libavcodec/mediacodec_wrapper.h
@@ -80,7 +80,7 @@ struct FFAMediaFormat {
     void (*setBuffer)(FFAMediaFormat* format, const char* name, void* data, size_t size);
 };
 
-FFAMediaFormat *ff_AMediaFormat_new(void);
+FFAMediaFormat *ff_AMediaFormat_new(int ndk);
 
 static inline int ff_AMediaFormat_delete(FFAMediaFormat* format)
 {
@@ -198,9 +198,9 @@ static inline char *ff_AMediaCodec_getName(FFAMediaCodec *codec)
     return codec->getName(codec);
 }
 
-FFAMediaCodec* ff_AMediaCodec_createCodecByName(const char *name);
-FFAMediaCodec* ff_AMediaCodec_createDecoderByType(const char *mime_type);
-FFAMediaCodec* ff_AMediaCodec_createEncoderByType(const char *mime_type);
+FFAMediaCodec* ff_AMediaCodec_createCodecByName(const char *name, int ndk);
+FFAMediaCodec* ff_AMediaCodec_createDecoderByType(const char *mime_type, int ndk);
+FFAMediaCodec* ff_AMediaCodec_createEncoderByType(const char *mime_type, int ndk);
 
 static inline int ff_AMediaCodec_configure(FFAMediaCodec* codec, const FFAMediaFormat* format, void* surface, void *crypto, uint32_t flags)
 {
diff --git a/libavcodec/mediacodecdec.c b/libavcodec/mediacodecdec.c
index 2c66f38541..2e07548b77 100644
--- a/libavcodec/mediacodecdec.c
+++ b/libavcodec/mediacodecdec.c
@@ -310,7 +310,7 @@ static av_cold int mediacodec_decode_init(AVCodecContext *avctx)
     FFAMediaFormat *format = NULL;
     MediaCodecH264DecContext *s = avctx->priv_data;
 
-    format = ff_AMediaFormat_new();
+    format = ff_AMediaFormat_new(0);
     if (!format) {
         av_log(avctx, AV_LOG_ERROR, "Failed to create media format\n");
         ret = AVERROR_EXTERNAL;
diff --git a/libavcodec/mediacodecdec_common.c b/libavcodec/mediacodecdec_common.c
index d6ce709dd8..1905e686bc 100644
--- a/libavcodec/mediacodecdec_common.c
+++ b/libavcodec/mediacodecdec_common.c
@@ -606,7 +606,7 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s,
     }
 
     av_log(avctx, AV_LOG_DEBUG, "Found decoder %s\n", s->codec_name);
-    s->codec = ff_AMediaCodec_createCodecByName(s->codec_name);
+    s->codec = ff_AMediaCodec_createCodecByName(s->codec_name, 0);
     if (!s->codec) {
         av_log(avctx, AV_LOG_ERROR, "Failed to create media decoder for type %s and name %s\n", mime, s->codec_name);
         ret = AVERROR_EXTERNAL;
