Android上使用NDK MediaCodec硬解码到纹理上

  • Post author:
  • Post category:其他


在之前写过在Android平台上通过MediaCodec的能力,硬解码到纹理上,然后在Unity上使用纹理进行渲染。



在Unity使用Android的MediaCodec硬解码能力进行纹理加载_XR风云的博客-CSDN博客


在做AR云渲染项目中,需要在Unity中利用Android的MediaCodec能力进行对视频进行硬解码,我们知道MediaCodec可以把视频流渲染到一个surface上,怎样把视频流中的纹理在Unity中使用呢?一个办法就是MediaCodec解码完成之后,可以把图像的缓存读取出来,在Unity中利用Texture2D 的LoadRawTextureData能力加载到一个纹理上去, 然后在经过YUV格式转换成RGB格式。这个方法非常耗性能,需要从GPU->CPU->GPU的链条,是非常耗



https://blog.csdn.net/grace_yi/article/details/116497338?spm=1001.2014.3001.5501


之前用的都是JAVA的接口,最近在写native SDK,需要直接使用C++的接口来进行解码,以及纹理处理,那最重要的就是怎样解码出来的画面直接写到纹理上去呢?

我们知道Android NDK提供了MediaCodec C++的解码接口的。跟java的接口非常类似。可以参考java的接口来进行编写。



https://developer.android.com/ndk/reference/group/media#amediacodec_configure


icon-default.png?t=M4AD
https://developer.android.com/ndk/reference/group/media#amediacodec_configure


当前最主要的还是AMediaCodec_configure这个配置接口,配置渲染到的surface上。这个surface怎样创建出来呢?

surface还是很容易创建出来的,但是怎样可以传入我们自己的textureId呢?这一块找了很多资料,没有直接找到C++的接口。那我就取了个巧,在C++中调用java的接口来进行操作。

1、首先我们利用JNI_OnLoad加载的时候,保存我们的global jvm。然后利用jvm来获取JNIEnv,代码如下。

JavaVM *global_jvm;
jobject g_surfaceTex_obj;
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
    signal(SIGSEGV, SIG_DFL);
    global_jvm = vm;
    return JNI_VERSION_1_6;
}
JNIEnv *get_env() {
    if (global_jvm == NULL) return NULL;
    JNIEnv *jni_env = NULL;
    int status = global_jvm->GetEnv((void **)&jni_env, JNI_VERSION_1_6);
    return jni_env;
}

2、有了JNIEnv之后,我们就可以调用java的接口来创建SurfaceTexture,Surface,调用UpdateTexImage接口等。

        int getTextureID() {
        GLuint texture;
        GLint currentTexture = 0;
        GL(glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &currentTexture))
        GL(glGenTextures(1, &texture));
        GL(glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture));
        GL(glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
        GL(glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
        GL(glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
        GL(glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
        GL(glBindTexture(GL_TEXTURE_EXTERNAL_OES, currentTexture))
        return texture;
    }

void createSureface(){
    JNIEnv *env = get_env();
    jclass surfacetexture_class = env->FindClass("android/graphics/SurfaceTexture");
    jmethodID surfacetexture_init = env->GetMethodID(surfacetexture_class, "<init>", "(I)V");
    jmethodID surfacetexture_setwh = env->GetMethodID(surfacetexture_class, "setDefaultBufferSize", "(II)V");
    jobject surfacetexture_obj = env->NewObject(surfacetexture_class, surfacetexture_init, (jint)getTextureID());
    env->CallVoidMethod(surfacetexture_obj, surfacetexture_setwh, width, height);
    jclass surface_class = env->FindClass("android/view/Surface");
    jmethodID surface_init = env->GetMethodID(surface_class, "<init>", "(Landroid/graphics/SurfaceTexture;)V");
    jobject surface_obj = env->NewObject(surface_class, surface_init, surfacetexture_obj);
    g_surfaceTex_obj = env->NewGlobalRef(surfacetexture_obj);

    env->DeleteLocalRef(surface_obj);
    env->DeleteLocalRef(surfacetexture_obj);
}

3、创建好Surface之后,在调用解码的接口AMediaCodec_configure的时候,知道nativeWindow

ANativeWindow* nativeWindow = ANativeWindow_fromSurface(env, surface);
AMediaCodec_configure(videoCodec, videoFormat, nativeWindow, NULL, 0);

4、调用UpdateTexImage更新每一帧数据

    JNIEnv *envT = get_env();
    jclass surfacetexture_class = envT->FindClass("android/graphics/SurfaceTexture");
    jmethodID surfacetexture_update = envT->GetMethodID(surfacetexture_class, "updateTexImage", "()V");
    envT->CallVoidMethod(g_surfaceTex_obj, surfacetexture_update);

这样就可以了。这样我们解码之后的数据直接在GPU中存到Texture上了,然后我们拿着TextureId就可以进行渲染了。这个是我们提供的C++版本的使用方法。JAVA版本的使用方法可以点击开头的链接。

参考文献:




omaf/NVRSurfaceTexture.cpp at master · nokiatech/omaf · GitHub


icon-default.png?t=M4AD
https://github.com/nokiatech/omaf/blob/master/Player/Sources/Player/VideoDecoder/Android/NVRSurfaceTexture.cpp





https://developer.android.com/ndk/reference/group/media


icon-default.png?t=M4AD
https://developer.android.com/ndk/reference/group/media




版权声明:本文为grace_yi原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。