视频实时OpenGL渲染并保存渲染结果合成MP4

来源:互联网 发布:宁波待遇好的企业 知乎 编辑:程序博客网 时间:2024/06/05 02:21
    这是一个能实时播放多个视频、图片在一个GL容器里的控件,通过这个控件,可以在一个view中绘制固定坐标、自由随机滚动的视频和图片,然后从该view中截取数据帧,实时保存成YUV格式的文件,最后合成MP4。

一、OpenGL 渲染视频模块

1.结构简介
a. GLEngine是一个全局控制GL绘制各个子view的类,结构图如下:
GLEngine结构图

b.Java层封装后的View控件结构如下:
这里写图片描述

    GLEngine直接提供接口给上层调用,通过该对象实现创建、绘制、释放子view,和获取GL绘制结果,以及释放整个GL。    MyGLView是对底层的封装,提供方法给Android直接使用。

2.工作原理

    底层GLEngine实例化后,会返回一个long型的对象句柄给上层的MyGLView,MyGLView对象就可以通过该句柄实现对底层GLEngine的引用。    MyGLView对象通过addStaticView()、addScrollView()方法调用底层对应的createStaticView()、createScrollView()函数,拿到子view long型的句柄,然提供给使用MyGLView的开发者保存下来,开发者就可以通过这些子view的句柄来绘制GL里面的各个子view。

二、视频编解码模块

  1. 结构简介
    a. GetRgbFremer
    MP4解码器,能从MP4文件中取出RGB帧,类结构图如下:
    这里写图片描述

    b.RgbToYuv420P
    对RGB帧转换成YUV420P帧的转换,并保存为文件,结构图如下:
    这里写图片描述

    c.H264Encoder
    能把YUV编码成H264,结构图如下:
    这里写图片描述

    d.Mp4Muxer
    视频复合器,能把AAC音频流和H264视频流合成MP4,结构图如下:
    这里写图片描述

三、视频编解码和OpenGL渲染整合使用指南

  1. 首选创建多个线程解码多个视频,获取到的帧数据缓存起来。
    /**     * 解码线程1     */    private FFGetRgbFramer mFFGetRgbFramer = new FFGetRgbFramer(mInMp4Path, mVideoWidth1, mVideoHeight1);    private byte[] mVideoData1;    private void decodeThread1() {        new Thread(new Runnable() {            @Override            public void run() {                while (mRun) {                    if (mVideoData1 == null) {                        mVideoData1 = mFFGetRgbFramer.getNextRgbFrame();                        if (mVideoData1 == null) {                            break;                        }                    }                }            }        }).start();    }…………
  1. 在SurfaceView的Renderer下的回调onSurfaceChanged下初始化MyGLView,并添加子view,拿到句柄保存下来,在回调onDrawFrame下把调用MyGLView对象的drawFrame()方法,并且把要绘制的子view对应的句柄和RGB帧数据传进去,该方法返回获取到的GL绘制结果,然后使用FFRgbToYuv420p保存成YUV文件,以备后续合成MP4使用。例如:
GLSurfaceView.Renderer mRenderer = new GLSurfaceView.Renderer() {        @Override        public void onSurfaceCreated(GL10 gl, EGLConfig config) {            mGLView.initGL();        }        @Override        public void onSurfaceChanged(GL10 gl, int width, int height) {            mGLView.onChangeGL(width,height);            mStaticHandle1 = mGLView.addStaticView(0, 0, mVideoWidth1, mVideoHeight1, width, height);            ……            ……            mHandles.clear();            mHandles.add(mStaticHandle1);            mHandles.add(mStaticHandle2);            ……        }        @Override        public void onDrawFrame(GL10 gl) {            if (mVideoData1 != null && mVideoData2 != null) {                List<byte[]> byteList = new ArrayList<>();                byteList.add(mVideoData1);                ……                mVideoData1 = null;                ……                byte[] rgbResultByte = mGLView.drawFrame(mHandles,byteList);                if (rgbResultByte != null) {                    mFFRgbToYuv420p.pushRgbData(rgbResultByte);                }            }        }    };

最后再分别利用H264Encoder、Mp4Muxer合成MP4。

阅读全文
0 0