# android_vip_filter_rtmp **Repository Path**: jsjxsy/android_vip_filter_rtmp ## Basic Information - **Project Name**: android_vip_filter_rtmp - **Description**: OpenGL + RTMP 实现 灵魂出窍和美颜功能,推送到B站 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-10-28 - **Last Updated**: 2025-02-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: Opengl, RTMP, Android ## README 1 离屏缓冲区FBO ![输入图片说明](pic/2.jpg) FBO(相当于数据)--->(绑定)texture纹理--》(绑定)图层 创建图层 GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D,0,GLES20.GL_RGBA,width,height, 0,GLES20.GL_RGBA,GLES20.GL_UNSIGNED_BYTE, null); 自己创建egl环境EGLBase 交换 mEglDisplay:虚拟屏幕, mEglSurface:eglSurface数据 EGL14.eglSwapBuffers(mEglDisplay, mEglSurface); 拿到CameraRender中opengl的一个上下文 EGLContext eglContext = EGL14.eglGetCurrentContext(); 传给EGLBase 也就是将GLSurfaceView的上下文传给新建的ELGBase作为上下文 GLSurfaceView中进行 int id = cameraFilter.onDraw(textures[0]); // id 1 textures[0] 2 mScreenFilter.onDraw(id); 在ELGBase中也要 mScreenFilter.onDraw(textureId); 必须在EGLBase的上下文的线程中进行 mHandler.post(new Runnable() { @Override public void run() { mEglBase.draw(textureId, timestamp); //从编码器的输出缓冲区获取编码后的数据就ok了 getCodec(false); } }); CameraFilter //因为这一层是摄像头后的第一层,所以需要使用扩展的 GL_TEXTURE_EXTERNAL_OES,这个针对外部设备 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId); //ScreenFilter 采用纹理坐标和CameraFilter采用的纹理坐标是一样的, ScreenFilter 还是外部纹理经过CPU Camerax --》 FBO(CameraFilter,不能显示到屏幕上,FBO的纹理Id) --> ScreenFilter(显示到屏幕上) EGL -----》 需要的是FBO的纹理Id,获取FBO的数据---》 ScreenFilter(不会显示到屏幕上) //不使用了 设值完了 方便 GLES20.glBindFramebuffer //必须解绑,不能重新绑定新的FBO GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,0); GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER,0); camera 如何与opengl的纹理绑定 1. opengl 创建纹理 绑定到camera的通过addTarget绑定 2. camera 获取SurfaceTexture 通过 mCameraTexure.attachToGLContext(textures[0]);创建纹理给opengl FBO:实现多个端的渲染 美颜功能: 对图像实行模糊化处理,但是并没有对图像图像区域进行人脸美颜 预览+录制(MediaCodec) 灵魂出窍功能: 对图片进行 rtmp库推送流 只要是硬件都是通过ByteBuffer传递数据 GLSurfaceView Render 这个已经过时 授权分两种: 运行期间允许,每次都询问 如果是运行期间都运行,则正常 第一安装没有获得camera权限就使用camera导致的问题 如果每次都询问,就报错: FATAL EXCEPTION: CameraX- Process: com.maniu.openglrecord, PID: 20892 java.lang.SecurityException: validateClientPermissionsLocked:1573: Caller "com.maniu.openglrecord" (PID 11017, UID 20892) cannot open camera "1" without camera permission at android.hardware.camera2.CameraManager.throwAsPublicException(CameraManager.java:1221) at android.hardware.camera2.CameraManager.openCameraDeviceUserAsync(CameraManager.java:655) camerax 权限问题导致的权限不足, Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x8 in tid 10111 (codec-gl), pid 9791 (iu.openglrecord) pid: 3595, tid: 4295, name: codec-gl >>> com.maniu.openglrecord <<< 2024-11-28 18:51:10.644 4299-4299 DEBUG pid-4299 A #00 pc 00000000000080b4 /data/app/~~F_WpaUejIBs8ThOTacS9Cg==/com.maniu.openglrecord-zZ9BRCakyPZWkz_WQNtsCQ==/lib/arm64/libnative-lib.so (prepareVideo(signed char*, int, Live*)+260) (BuildId: d31709fc95a884e5ef81a61c2eca6616d92793db) 2024-11-28 18:51:10.644 4299-4299 DEBUG pid-4299 A #01 pc 00000000000087ec /data/app/~~F_WpaUejIBs8ThOTacS9Cg==/com.maniu.openglrecord-zZ9BRCakyPZWkz_WQNtsCQ==/lib/arm64/libnative-lib.so (sendVideo(signed char*, int, long)+80) (BuildId: d31709fc95a884e5ef81a61c2eca6616d92793db) 2024-11-28 18:51:10.644 4299-4299 DEBUG pid-4299 A #02 pc 00000000000088a0 /data/app/~~F_WpaUejIBs8ThOTacS9Cg==/com.maniu.openglrecord-zZ9BRCakyPZWkz_WQNtsCQ==/lib/arm64/libnative-lib.so (Java_com_maniu_openglrecord_MediaEncoderAndPush_sendData+64) (BuildId: d31709fc95a884e5ef81a61c2eca6616d92793db) 2024-11-28 18:51:10.644 4299-4299 DEBUG pid-4299 A #10 pc 0000000000002d44 [anon:dalvik-classes3.dex extracted in memory from /data/app/~~F_WpaUejIBs8ThOTacS9Cg==/com.maniu.openglrecord-zZ9BRCakyPZWkz_WQNtsCQ==/base.apk!classes3.dex] (com.maniu.openglrecord.MediaEncoderAndPush.codec+112) 2024-11-28 18:51:10.644 4299-4299 DEBUG pid-4299 A #16 pc 0000000000002cbc [anon:dalvik-classes3.dex extracted in memory from /data/app/~~F_WpaUejIBs8ThOTacS9Cg==/com.maniu.openglrecord-zZ9BRCakyPZWkz_WQNtsCQ==/base.apk!classes3.dex] (com.maniu.openglrecord.MediaEncoderAndPush.access$600+0) 2024-11-28 18:51:10.644 4299-4299 DEBUG pid-4299 A #21 pc 0000000000002bb6 [anon:dalvik-classes3.dex extracted in memory from /data/app/~~F_WpaUejIBs8ThOTacS9Cg==/com.maniu.openglrecord-zZ9BRCakyPZWkz_WQNtsCQ==/base.apk!classes3.dex] (com.maniu.openglrecord.MediaEncoderAndPush$2.run+26) 1.错误代号:signal 11 (SIGSEGV), code 1 (SEGV_MAPERR),一般都是空指针错误 url链接失败,live对象没有初始化导致的问题 推流直播 rtmp://10.9.86.140:1935/livehime 观看直播 https://live.bilibili.com/1729548788 GPU中的数据是如何流向MediaCodec mSurface= mediaCodec.createInputSurface(); eglEnv = new EGLBase(mContext, mWidth, mHeight, mSurface, mGlContext); // ? 交换surface EGL14.eglSwapBuffers(mEglDisplay, mEglSurface); 通过eglSwapBuffers将opengl中surface交给mediaCodec的surface进行编码】 那怎么样才能绘制到MediaCodec的Surface当中去呢,我们知道录制视频是在一个线程中,显示图像(GLSurfaceView)是在另一个GLThread线程中进行的,所以这两者的EGL环境也不同,但是两者又共享上下文资源,录制现场中画面的绘制需要用到显示线程中的texture等,那么这个线程就需要我们做这些: 1.配置录制使用的EGL环境(可以参照GLSurfaceView怎么配置的) 2.将显示的图像绘制到MediaCodec中的Surface中 3.编码(h.264)与复用(mp4)的工作 ScreenFilter --》 video_frag //GLSurfaceView中切换到GLThread线程 cameraView.queueEvent(new Runnable() { @Override public void run() { if (isChecked) { beautyFilter = new BeautyFilter(cameraView.getContext()); beautyFilter.setSize(cameraView.getWidth(), cameraView.getHeight()); } else { beautyFilter.release(); beautyFilter = null; } } });