begeekmyfriend / yasea

RTMP live streaming client for Android
MIT License
4.87k stars 1.32k forks source link

关于取得美颜数据的效率问题 #340

Open a483210 opened 7 years ago

a483210 commented 7 years ago

我看您是通过glReadPixels获得像素的 GLES20.glViewport(0, 0, mInputWidth, mInputHeight); GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mGLFboId[0]); GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); GLES20.glReadPixels(0, 0, mInputWidth, mInputHeight, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, mGLFboBuffer); GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); GLES20.glViewport(0, 0, mOutputWidth, mOutputHeight);

但是在有些机子上效率还是不够,尽管我已经用了beautify_fragment_low 目前只有发现grafika的方法效率可以,但是我又发现MediaCodec的KEY_FRAME_RATE设置了无效,我查了google说它是由输入源确定的(比如摄像头),所以如果我想录制15帧视频,就只有2个方法 1、修改Camera的fps,但是当我设置成为15帧时会明显出现卡顿 2、先编码成h264然后在解码成yuvi420,最后在进行一次编码,这样做明显非常多余 请问您有什么好方法吗?

begeekmyfriend commented 7 years ago

你说的没错,glReadPixels的效率问题,#324 已经吐槽过了,并没有太好的兼容性方法,估计只有魔改了~

只能说一些机子上设备驱动太差了(glReadPixels也可以看做设备驱动读接口),不过建议你对比一下不开美颜时的帧率,美颜再怎么优化也不可能比原始帧率高。如果原始帧率就很低,那就不单单是glReadPixels的问题,估计只能考虑换机型了。

a483210 commented 7 years ago

谢谢您的回答,我用glReadPixels测试过一些机型,在索尼三星等机子上效率非常高,但是在国产机子上效率就非常差,这是不是因为国产的接口优化差呢? 还有从native上gles动刀大概怎么做?我不太理解您的意思。

notedit commented 7 years ago

你可以google EGLImageKHR

begeekmyfriend commented 7 years ago

建议你先跑一个non-gpuimage分支测试一下fps,如果还是太差就别浪费时间了。

a483210 commented 7 years ago

@notedit 事实上我查找过EGLImageKHR,但是我找不到GraphicBuffer.h,我看他好像在android的源码里面,我在ndk里面引用不到,然后有人说从源码里提取,事实上我觉得这不太靠谱。所以我最终放弃了EGLImageKHR。 http://stackoverflow.com/questions/23261662/how-to-use-graphicbuffer-in-android-ndk 例子 您有什么好方法可以解决该问题吗? @begeekmyfriend 我测试过https://github.com/wuhaoyu1990/MagicCamera 项目采用low的情况下大部分机子都能保持流畅,如果实在没办法我只能用grafika的方法了。

begeekmyfriend commented 7 years ago

Grafika用什么方式将GPU memory的数据拷贝到CPU memory的?

a483210 commented 7 years ago

它通过MediaCodec format.setInteger(MediaFormat.KEY_COLOR_FORMAT,MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface) 将surface里的数据直接编码 https://github.com/wuhaoyu1990/MagicCamera/blob/master/Project-AndroidStudio/magicfilter/src/main/java/com/seu/magicfilter/encoder/video/VideoEncoderCore.java 详细做法

notedit commented 7 years ago

Grafika 的做法必须4.3 以上

begeekmyfriend commented 7 years ago

哦,就是上面第二种啊,多一道编解码,效果反而比glReadPixels好,太悲催了

notedit commented 7 years ago

EGLImageKHR 为什么不靠谱 我身边认识的公司 就有用的

begeekmyfriend commented 7 years ago

@notedit Grafika的方式要解码一遍,加特效后还要再编码一遍,这种效率反而好也是没谁了

a483210 commented 7 years ago

@notedit 您知道使用EGLImageKHR 具体应该怎么做吗?我对这里不是十分了解

notedit commented 7 years ago

知道 @a483210

a483210 commented 7 years ago

@notedit 额,能教下我吗?拜托了!

notedit commented 7 years ago

不是几行代码可以搞定的 之前搞了很长时间才搞定

4.3 以下的机器可以不支持了, 直接渲染到Surface 上 然后用Mediacodec 就可以

begeekmyfriend commented 7 years ago

@a483210 意思就是放弃glReadPixels使用MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface

a483210 commented 7 years ago

谢谢2位,我现在已经在用Mediacodec 写了,除了做法难看点,o(╯□╰)o

begeekmyfriend commented 7 years ago

@a483210 你理解错了,这段代码不要了,FBO去掉,直接读取surface,一次编码即可,不需要再解码

a483210 commented 7 years ago

我知道可以直接编码,但是我不知道怎么控制fps,设置成15帧它依然会编码出30帧的h264。 我之前google过好像是fps会根据输入源来确定,所以我才会再次解码,然后自己去过滤多余的帧

begeekmyfriend commented 7 years ago

试试修改摄像头的帧率设置

a483210 commented 7 years ago

我试过了,的确可以,但是如果我修改为低于24帧,就会感到明显的卡顿,所以这里我非常纠结

notedit commented 7 years ago

我这边设置15帧 也没感觉卡

a483210 commented 7 years ago

@notedit 额,您把摄像头浏览的fps设置成15帧不会感觉稍微有些卡顿么

notedit commented 7 years ago

不会 在音视频通话里面15帧 很正常

a483210 commented 7 years ago

@notedit 好的,我明天实验下,非常感谢

a483210 commented 7 years ago

@notedit 我测试了下设置摄像头为15帧,但是从MediaCodec得到sps pps显示还是30帧,用FFmpeg检测出来的是24帧,也就是说当我放这个h264时是快进的

begeekmyfriend commented 7 years ago

你的设备是手机?报上名来

a483210 commented 7 years ago

索尼z2 应该说我没理解MediaCodec的sps pps是靠什么确定的

begeekmyfriend commented 7 years ago

摄像头和编码器都设成15吗?

a483210 commented 7 years ago

对,我也试过低于15帧的,也一样没用

jtyang commented 7 years ago

请问下MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface具体要咋改呢?试了下@begeekmyfriend说的,“这段代码不要了”,貌似预览都有问题。

a483210 commented 7 years ago

@jtyang 你可以看下我写的《Android 关于美颜/滤镜 从OpenGl录制视频的一种方案》希望能对你有所帮助

hirudo-zy commented 7 years ago

@notedit 您好,想向您请教下EGLImageKHR获取数据的问题。当我使用 buffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &ptr); memcpy(pixels, ptr, wh4); buffer->unlock(); 获取数据时,我只能得到一个数据为空的ptr(有地址),不知道您遇到过这个问题吗?有什么好的建议吗? Stack Overflow上类似的问题https://stackoverflow.com/questions/21151259/replacing-glreadpixels-with-egl-khr-image-base-for-faster-pixel-copy?noredirect=1&lq=1

liouvilles commented 9 months ago

23年再回一句用ImageReader读合适吗