4
votes

The NDK documentation says this function is available (https://developer.android.com/ndk/reference/group/media#group___media_1ga8eb3e60bb5c76e90d7652dff636dd17b), and indeed it can be called from java code, but it produces an "unresolved function" [In Android Studio] error from C++ code.

I'm trying to feed an MJPEG stream to the MediaCodec and have the MediaMuxer record an MP4 video from it. I've found limited examples of how to do similar things in Java code, but ZERO examples of how to do anything similar in Native code. So I've tried to duplicate the Java examples in Native code. This particular function call seems to be relatively important to accomplishing my goal, and I can successfully call: MediaCodec.createInputSurface() from java code. I've looked at media/NdkMediaCodec.h and createInputSurface() is NOT listed.

Am I going about this the wrong way, is there something I'm not understanding? Here is the Native code:

jboolean Java_com_business_rky_tht_1app_MjpegView_StartMP4Record(JNIEnv *env, jclass clazz, jobject surface, jstring filename) {

AMediaCodec *Native_codec = AMediaCodec_createEncoderByType("video/avc");
if (Native_codec != NULL)
{
    AMediaFormat *Media_Format = AMediaFormat_new();
    if (Media_Format != NULL) 
    {
        AMediaCrypto *Media_Crypto = NULL;
        uint32_t Config_Flags = AMEDIACODEC_CONFIGURE_FLAG_ENCODE;
        ANativeWindow *Native_Window  = ANativeWindow_fromSurface(env, surface);

        if(Native_Window == NULL)
            return JNI_FALSE;

        int32_t Frame_Height = ANativeWindow_getHeight(Native_Window);
        int32_t Frame_Width  = ANativeWindow_getWidth(Native_Window);

        // Make the work area of the frame a multiple of 64
        int32_t Image_Height = (Frame_Height & (0xFFFFFFC0) );
        int32_t Image_Width = (Frame_Width & (0xFFFFFFC0) );
        int32_t Color_Format = ANativeWindow_getFormat(Native_Window);

        // No limits for input size
        // AMediaFormat_setInt32(format, "max-input-size", 0);
        AMediaFormat_setInt32(Media_Format, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, 0);
        AMediaFormat_setInt32(Media_Format, AMEDIAFORMAT_KEY_MAX_HEIGHT, Frame_Height);
        AMediaFormat_setInt32(Media_Format, AMEDIAFORMAT_KEY_MAX_WIDTH, Frame_Width);
        AMediaFormat_setString(Media_Format, AMEDIAFORMAT_KEY_MIME, "video/avc");
        AMediaFormat_setInt32(Media_Format, AMEDIAFORMAT_KEY_HEIGHT, Frame_Height);
        AMediaFormat_setInt32(Media_Format, AMEDIAFORMAT_KEY_WIDTH, Frame_Width);

        // ** For simplicity we just crop from right and bottom,
        // ** to center the image 1/2 the differences should be
        // ** cropped from all four sides
        AMediaFormat_setInt32(Media_Format, "crop-left" , 0);
        AMediaFormat_setInt32(Media_Format, "crop-top" , 0);
        AMediaFormat_setInt32(Media_Format, "crop-right" , (Image_Width - 1));
        AMediaFormat_setInt32(Media_Format, "crop-bottom" , (Image_Height - 1));
        AMediaFormat_setInt32(Media_Format,AMEDIAFORMAT_KEY_STRIDE,Frame_Width);

        AMediaFormat_setInt32(Media_Format, AMEDIAFORMAT_KEY_COLOR_FORMAT, Color_Format);

        media_status_t rc = AMediaCodec_configure(Native_codec, Media_Format, NULL, NULL, Config_Flags);

        if (AMEDIA_OK == rc) {

            AMediaCodec_createInputSurface(Native_codec, &Native_Window);
                            //  ^^^ UNRESOLVED - UNRESOLVED - UNRESOLVED ^^^


            // Would start codec and create muxer
            // .
            // .
            // .
            return JNI_TRUE;
        }else{
            AMediaCodec_delete(Native_codec);
            ANativeWindow_release(Native_Window);
            return JNI_FALSE;
        }
    } // End - if (Media_Format != NULL)
} // End - if (Native_codec != NULL)

} // End - StartMP4Rec


Build Error:

Build command failed. Error while executing process C:\Users\rky\AppData\Local\Android\Sdk\ndk-bundle\ndk-build.cmd with arguments {NDK_PROJECT_PATH=null APP_BUILD_SCRIPT=C:\Users\rky\AndroidStudioProjects\THT_App\app\src\main\jni\Android.mk NDK_APPLICATION_MK=C:\Users\rky\AndroidStudioProjects\THT_App\app\src\main\jni\Application.mk APP_ABI=arm64-v8a NDK_ALL_ABIS=arm64-v8a NDK_DEBUG=1 APP_PLATFORM=android-18 NDK_OUT=C:/Users/rky/AndroidStudioProjects/THT_App/app/build/intermediates/ndkBuild/debug/obj NDK_LIBS_OUT=C:\Users\rky\AndroidStudioProjects\THT_App\app\build\intermediates\ndkBuild\debug\lib C:/Users/rky/AndroidStudioProjects/THT_App/app/build/intermediates/ndkBuild/debug/obj/local/arm64-v8a/libMjpgToMP4.so} [arm64-v8a] Compile++ : MjpgToMP4 <= MjpgToMP4.cpp C:/Users/rky/AndroidStudioProjects/THT_App/app/src/main/jni/MjpgToMP4/MjpgToMP4.cpp:320:17: error: use of undeclared identifier 'AMediaCodec_createInputSurface'; did you mean 'AMediaCodec_setOutputSurface'? AMediaCodec_createInputSurface(Native_codec, &Native_Window); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AMediaCodec_setOutputSurface C:/Users/rky/AppData/Local/Android/Sdk/ndk-bundle/build//../sysroot/usr/include\media/NdkMediaCodec.h:266:16: note: 'AMediaCodec_setOutputSurface' declared here media_status_t AMediaCodec_setOutputSurface(AMediaCodec*, ANativeWindow* surface) __INTRODUCED_IN(21); ^ C:/Users/rky/AndroidStudioProjects/THT_App/app/src/main/jni/MjpgToMP4/MjpgToMP4.cpp:320:62: error: cannot initialize a parameter of type 'ANativeWindow ' with an rvalue of type 'ANativeWindow ' AMediaCodec_createInputSurface(Native_codec, &Native_Window); ^~~~~~~~~~~~~~ C:/Users/rky/AppData/Local/Android/Sdk/ndk-bundle/build//../sysroot/usr/include\media/NdkMediaCodec.h:266:74: note: passing argument to parameter 'surface' here media_status_t AMediaCodec_setOutputSurface(AMediaCodec, ANativeWindow* surface) __INTRODUCED_IN(21); ^ 2 errors generated. make: * [C:/Users/rky/AndroidStudioProjects/THT_App/app/build/intermediates/ndkBuild/debug/obj/local/arm64-v8a/objs-debug/MjpgToMP4/MjpgToMP4.o] Error 1

2
What is your Ndk version? try to update your NDK to the latest oneE.Abdel
NDK version is 18.1.5063045, according to developer.android.com/ndk/downloads Latest Stable Version is r18b, and the SDK manager does not show any newer version available.RKYoung

2 Answers

3
votes

These functions were introduced at API level 21 26, but your build specifies APP_PLATFORM=android-18. Make sure that you don't set minSdkVersion too low in your build.gradle.

-1
votes

[Solved] As Alex Cohn's edited answer indicates. Despite what the documentation says AMediaCodec_createInputSurface(...) was introduced in API 26 NOT 21. If I edit the app gradle.build to: "minSdkVersion 26," AMediaCodec_createInputSurface(...) IS resolved. If I change it to: "minSdkVersion 25," AMediaCodec_createInputSurface(...) IS NOT resolved. In short the documentation is wrong.