[chatGPT] 如何通过JNI在Android上显示实时视频流

背景

相机拍摄的画面通过local socket 获取,所以C++的代码可以轻易的获取到每一帧视频数据,需要通过JNI 让 Android显示出来,方法有两种,一种是在Android内创建回调函数使用Bitmap 和ImageView 进行赋值显示,另一种也就是ChatGPT完成的,Android将surface 传递到JNI层内,C++来完成赋值和渲染,后者效率更高。
本文通过和ChatGPT的对话来描述代码的实现过程。

正文

礼貌性问候一下。
在这里插入图片描述
开始吧:
在这里插入图片描述

MediaPlayer mediaPlayer = new MediaPlayer();
SurfaceView surfaceView = findViewById(R.id.surface_view);
SurfaceHolder surfaceHolder = surfaceView.getHolder();

mediaPlayer.setDataSource("http://your_video_stream.mp4");
mediaPlayer.setDisplay(surfaceHolder);
mediaPlayer.prepare();
mediaPlayer.start();

在这里插入图片描述
在这里插入图片描述

layout xml
<SurfaceView
    android:id="@+id/surface_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
java
SurfaceView surfaceView = findViewById(R.id.surface_view);
SurfaceHolder surfaceHolder = surfaceView.getHolder();
C++
#include <jni.h>
#include <android/native_window_jni.h>
#include <android/native_window.h>
#include <unistd.h>

// ...

extern "C"
JNIEXPORT void JNICALL
Java_com_example_NativeVideoPlayer_playVideo(JNIEnv *env, jobject instance, jobject surface) {
    ANativeWindow *window = ANativeWindow_fromSurface(env, surface);
    ANativeWindow_setBuffersGeometry(window, 720, 480, WINDOW_FORMAT_RGBA_8888);

    while (true) {
        // Capture and decode the video stream
        // ...

        // Render the decoded video frame to the surface
        // ...

        // Sleep for a short period of time
        usleep(16000);
    }

    ANativeWindow_release(window);
}
java
public class NativeVideoPlayer {
    static {
        System.loadLibrary("native-video-player");
    }

    public native void playVideo(SurfaceHolder surfaceHolder);
}

// ...

NativeVideoPlayer player = new NativeVideoPlayer();
player.playVideo(surfaceHolder);

总结一:

整体思路是创建一个surface 然后将surface 的 surface holder 传递到 JNI。
但是没有写如何赋值给surface holder 那我们继续问。

追问:

在这里插入图片描述

C++
jobject surface = env->GetObjectField(surfaceHolder, surfaceFieldID);
// ...
ANativeWindow *nativeWindow = ANativeWindow_fromSurface(env, surface);
//...
ANativeWindow_setBuffersGeometry(nativeWindow, width, height, format);
//...
ANativeWindow_Buffer buffer;
if (ANativeWindow_lock(nativeWindow, &buffer, NULL) == 0) {
  // Assign video stream buffer to the ANativeWindow
  // ...

  ANativeWindow_unlockAndPost(nativeWindow);
}

在这里插入图片描述

C++
if (ANativeWindow_lock(nativeWindow, &buffer, NULL) == 0) {
  // Assign video stream buffer to the ANativeWindow
  uint8_t *dst = static_cast<uint8_t *>(buffer.bits);
  memcpy(dst, yuvBuffer, buffer.stride * buffer.height);

  ANativeWindow_unlockAndPost(nativeWindow);
}

总结二:

到这里基本的代码已经全部写出来了,只需要每次把图像数据写入 到 window 的buffer 中就好。
但是难免有什么不理解或者不对的地方,那我们就继续让它答疑解惑吧。

答疑解惑

首先有一个问题,就是我没有从surfaceHolder找到surface。

C++
jclass surfaceHolderClass = env->GetObjectClass(surfaceHolder);
jfieldID surfaceFieldID = env->GetFieldID(surfaceHolderClass, "mSurface", "Landroid/view/Surface;");

jobject surface = env->GetObjectField(surfaceHolder, surfaceFieldID);

在这里插入图片描述

在这里插入图片描述
然后我就去找新的接口,发现一个getSurface的接口。我自己做了下面的调整:

jmethodID getSurfaceMethodID = env->GetMethodID(surface_hoder_class, "getSurface", "()Landroid/view/Surface;");
jobject surface = env->CallObjectMethod(surface_holder, getSurfaceMethodID);
if(surface == nullptr){}

然后反问它
在这里插入图片描述
剩下的就是学习和真的答疑解惑了:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
到这里应该就结束了
.

画蛇添足 视频不显示黑屏

我其实画蛇添足还出了一个问题,ChatGPT 没帮我解决我自己找到的,后来我告诉机器人,下次遇到这样的事情,可以提醒一下其他人,看吧:
在这里插入图片描述
因为用到OpenGL 所以要加载一些依赖项。
在这里插入图片描述

最后感叹科技的更新速度,真的程序员都可能会被替代,下一个时代最大的问题应该是劳动力过剩,导致社会性结构改变,一部分人会被社会性抛弃。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值