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