目录
- 背景
- 正文
- layout xml
- java
- C++
- java
- 总结一:
- 追问:
- C++
- C++
- 总结二:
- 答疑解惑
- C++
- 画蛇添足 视频不显示黑屏
- 最后感叹科技的更新速度,真的程序员都可能会被替代,下一个时代最大的问题应该是劳动力过剩,导致社会性结构改变,一部分人会被社会性抛弃。
背景
相机拍摄的画面通过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
<SurfaceViewandroid: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 timeusleep(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 ANativeWindowuint8_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 所以要加载一些依赖项。