欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android使用OpenGL和MediaCodec錄制功能

 更新時(shí)間:2025年04月07日 10:29:52   作者:布拉德很帥  
OpenGL是一個(gè)跨平臺(tái)的操作GPU的API,但OpenGL需要本地視窗系統(tǒng)進(jìn)行交互,這就需要一個(gè)中間控制層, EGL就是連接OpenGL ES和本地窗口系統(tǒng)的接口,引入EGL就是為了屏蔽不同平臺(tái)上的區(qū)別,這篇文章主要介紹了Android使用OpenGL和MediaCodec錄制功能,需要的朋友可以參考下

一,什么是opengl

Open Graphics Library     圖形領(lǐng)域的工業(yè)標(biāo)準(zhǔn),是一套跨編程語言、跨平臺(tái)的、專業(yè)的圖形編程(軟件)接口。它用于二維、三維圖像,是一個(gè)功能強(qiáng)大,調(diào)用方便的底層圖形庫。     

與硬件無關(guān)??梢栽诓煌钠脚_(tái)如Windows、Linux、Mac、Android、IOS之間進(jìn)行移植。因此,支持OpenGL的軟件具有很好的移植性,可以獲得非常廣泛的應(yīng)用。

OpenGL ES 1.0 和 1.1 :Android 1.0和更高的版本支持這個(gè)API規(guī)范。 OpenGL ES 2.0 :Android 2.2(API 8)和更高的版本支持這個(gè)API規(guī)范。 OpenGL ES 3.0 :Android 4.3(API 18)和更高的版本支持這個(gè)API規(guī)范。 OpenGL ES 3.1 : Android 5.0(API 21)和更高的版本支持這個(gè)API規(guī)范

還須要由設(shè)備制造商提供了實(shí)現(xiàn)支持 目前廣泛支持的是2.0 <uses-feature android:glEsVersion="0x00020000" android:required="true"/>

二,什么是Android OpenGL ES

針對手機(jī)、PDA和游戲主機(jī)等嵌入式設(shè)備而設(shè)計(jì)的OpenGL API 子集。

GLSurfaceView

繼承至SurfaceView,它內(nèi)嵌的surface專門負(fù)責(zé)OpenGL渲染。     管理Surface與EGL     允許自定義渲染器(render)。     讓渲染器在獨(dú)立的線程里運(yùn)作,和UI線程分離。      支持按需渲染(on-demand)和連續(xù)渲染(continuous)。

OpenGL是一個(gè)跨平臺(tái)的操作GPU的API,但OpenGL需要本地視窗系統(tǒng)進(jìn)行交互,這就需要一個(gè)中間控制層, EGL就是連接OpenGL ES和本地窗口系統(tǒng)的接口,引入EGL就是為了屏蔽不同平臺(tái)上的區(qū)別。

三, OpenGL 繪制流程

其實(shí)就是一個(gè)可編程管線pipline

渲染管線做的事情就是讓計(jì)算機(jī)完成圖形功能。 固定管線:程序員只能設(shè)置參數(shù)。比如 f(x)=axx + bx + c程序員只能設(shè)置a,b,c的值,卻不能修改這個(gè)公式。 可編程管線:程序員掌控一切。

四, OpenGL坐標(biāo)系

五, OpenGL 著色器

著色器(Shader)是運(yùn)行在GPU上的小程序。頂點(diǎn)著色器(vertex shader)  如何處理頂點(diǎn)、法線等數(shù)據(jù)的小程序。片元著色器(fragment shader)     如何處理光、陰影、遮擋、環(huán)境等等對物體表面的影響,最終生成一副圖像的小程序

六, GLSL編程語言

七,使用MediaCodec錄制在Opengl中渲染架構(gòu)

八,代碼實(shí)現(xiàn)

8.1 自定義渲染view繼承GLSurfaceView

public class TigerView extends GLSurfaceView {
    private TigerRender mTigerRender;
    //默認(rèn)正常速度
    private Speed mSpeed = Speed.MODE_NORMAL;
    public void setSpeed(Speed speed) {
        mSpeed = speed;
    }
    public enum Speed {
        MODE_EXTRA_SLOW, MODE_SLOW, MODE_NORMAL, MODE_FAST, MODE_EXTRA_FAST
    }
    public TigerView(Context context) {
        super(context);
    }
    public TigerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        /**
         * 設(shè)置egl版本
         */
        setEGLContextClientVersion(2);
        /**
         * 設(shè)置渲染器
         */
        mTigerRender = new TigerRender(this);
        setRenderer(mTigerRender);
        /**
         * 設(shè)置按需渲染,當(dāng)我們調(diào)用requestRender()的時(shí)候就會(huì)調(diào)用GlThread回調(diào)一次onDrawFrame()
         */
        setRenderMode(RENDERMODE_WHEN_DIRTY);
    }
    public void startRecord() {
        float speed = 1.f;
        switch (mSpeed) {
            case MODE_EXTRA_SLOW:
                speed = 0.3f;
                break;
            case MODE_SLOW:
                speed = 0.5f;
                break;
            case MODE_NORMAL:
                speed = 1.f;
                break;
            case MODE_FAST:
                speed = 1.5f;
                break;
            case MODE_EXTRA_FAST:
                speed = 3.f;
                break;
        }
        mTigerRender.startRecord(speed);
    }
    public void stopRecord() {
        mTigerRender.stopRecord();
    }
}

8.2 自定義渲染器TigerRender

public class TigerRender implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener {
    private final TigerView mView;
    private CameraHelper mCameraHelper;
    private SurfaceTexture mSurfaceTexture;
    float[] mtx = new float[16];
    private ScreeFilter mScreeFilter;
    private int[] mTextures;
    private CameraFilter mCameraFilter;
    private MediaRecorder mMediaRecorder;
    public TigerRender(TigerView tigerView) {
        mView = tigerView;
    }
    /**
     * 畫布創(chuàng)建好了
     *
     * @param gl     the GL interface. Use <code>instanceof</code> to
     *               test if the interface supports GL11 or higher interfaces.
     * @param config the EGLConfig of the created surface. Can be used
     *               to create matching pbuffers.
     */
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        mCameraHelper = new CameraHelper(Camera.CameraInfo.CAMERA_FACING_BACK);
        //準(zhǔn)備好攝像頭繪制的畫布
        //通過open gl創(chuàng)建一個(gè)紋理id
        mTextures = new int[1];
        GLES20.glGenTextures(mTextures.length, mTextures, 0);
        mSurfaceTexture = new SurfaceTexture(mTextures[0]);
        //設(shè)置有一幀新的數(shù)據(jù)到來的時(shí)候,回調(diào)監(jiān)聽
        mSurfaceTexture.setOnFrameAvailableListener(this);
        //必須要在GlThread里面創(chuàng)建著色器程序
        mCameraFilter = new CameraFilter(mView.getContext());
        mScreeFilter = new ScreeFilter(mView.getContext());
        EGLContext eglContext = EGL14.eglGetCurrentContext();
        mMediaRecorder = new MediaRecorder(mView.getContext(), "/mnt/sdcard/test.mp4", CameraHelper.HEIGHT, CameraHelper.WIDTH, eglContext);
    }
    /**
     * 畫布發(fā)生改變
     *
     * @param gl     the GL interface. Use <code>instanceof</code> to
     *               test if the interface supports GL11 or higher interfaces.
     * @param width
     * @param height
     */
    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        mCameraHelper.startPreview(mSurfaceTexture);
        mCameraFilter.onReady(width, height);
        mScreeFilter.onReady(width, height);
    }
    /**
     * 畫畫
     *
     * @param gl the GL interface. Use <code>instanceof</code> to
     *           test if the interface supports GL11 or higher interfaces.
     */
    @Override
    public void onDrawFrame(GL10 gl) {
        //告訴open gl需要把屏幕清理成 什么樣子的顏色
        GLES20.glClearColor(0, 0, 0, 0);
        //開始真正的屏幕顏色清理,也就是上一次設(shè)置的屏幕顏色
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        //把攝像頭采集的數(shù)據(jù)輸出出來
        //更新紋理,然后我們才可以使用opengl從SurfaceTexure當(dāng)中獲取數(shù)據(jù),進(jìn)行渲染
        mSurfaceTexture.updateTexImage();
        //mSurfaceTexture比較特殊,在設(shè)置坐標(biāo)的時(shí)候,需要一個(gè)變換矩陣,使用的是特殊的采樣器samplerExternalOES
        //這種采樣器,正常的是sample2D
        mSurfaceTexture.getTransformMatrix(mtx);
        mCameraFilter.setMatrix(mtx);
        int id = mCameraFilter.onDrawFrame(mTextures[0]);
        //在這里添加各種效果,相當(dāng)于責(zé)任鏈
        //開始畫畫
        mScreeFilter.onDrawFrame(id);
        mMediaRecorder.encodeFrame(id, mSurfaceTexture.getTimestamp());
    }
    /**
     * SurfaceTexture有一個(gè)新的有效的圖片的時(shí)候會(huì)被回調(diào),此時(shí)可以把這個(gè)數(shù)據(jù)回調(diào)給GLSurfaceView的onDrawFrame
     *
     * @param surfaceTexture
     */
    @Override
    public void onFrameAvailable(SurfaceTexture surfaceTexture) {
        if (mView != null) {
            //開始渲染,有一幀新的圖像,就開始調(diào)用GLSurfaceView的onDrawFrame進(jìn)行繪制
            mView.requestRender();
        }
    }
    public void startRecord(float speed) {
        try {
            mMediaRecorder.start(speed);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public void stopRecord() {
        mMediaRecorder.stop();
    }
}

8.3 創(chuàng)建編碼器MediaRecorder

/**
 * 視頻錄制
 */
public class MediaRecorder {
    private final Context mContext;
    private final String mPath;
    private final int mWidth;
    private final int mHeight;
    private final EGLContext mEglContext;
    private MediaCodec mMediaCodec;
    private Surface mInputSurface;
    private MediaMuxer mMediaMuxer;
    private Handler mHandler;
    private EGLBase mEglBase;
    private boolean isStart;
    private int index;
    private float mSpeed;
    /**
     * @param context
     * @param path    視頻保存地址
     * @param width   視頻寬
     * @param height  視頻高
     */
    public MediaRecorder(Context context, String path, int width, int height, EGLContext eglContext) {
        mContext = context.getApplicationContext();
        mPath = path;
        mWidth = width;
        mHeight = height;
        mEglContext = eglContext;
    }
    /**
     * 開始錄制視頻
     */
    public void start(float speed) throws IOException {
        /**
         * 配置MediaCodec編碼器,視頻編碼的寬,高,幀率,碼率
         * 錄制成mp4格式,視頻編碼格式是h264 MIMETYPE_VIDEO_AVC 高級編碼
         */
        mSpeed = speed;
        MediaFormat videoFormat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, mWidth, mHeight);
        //配置碼率 1500kbs
        videoFormat.setInteger(MediaFormat.KEY_BIT_RATE, 1500_000);
        //幀率
        videoFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 20);
        //關(guān)鍵字間隔
        videoFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 20);
        //創(chuàng)建視頻高級編碼器
        mMediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
        //因?yàn)槭菑腟urface中讀取的,所以不需要設(shè)置這個(gè)顏色格式
        videoFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
        //配置編碼器,CONFIGURE_FLAG_ENCODE,
        mMediaCodec.configure(videoFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
        //交給虛擬屏幕,通過opengl 將預(yù)覽的紋理繪制到這一個(gè)虛擬屏幕中,這樣子Mediacodc 就會(huì)自動(dòng)編碼這一幀圖像
        mInputSurface = mMediaCodec.createInputSurface();
        //mp4 播放流程  解復(fù)用--》解碼 》繪制
        //mp4 編碼流程  封裝器--》編碼
        //MUXER_OUTPUT_MPEG_4 MP4格式封裝器,將h.264通過他寫出到文件就可以了
        mMediaMuxer = new MediaMuxer(mPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
        /**
         * 配置EGL環(huán)境,也就是配置我們的虛擬屏幕環(huán)境
         */
        HandlerThread handlerThread = new HandlerThread("ViewoCodec");
        handlerThread.start();
        Looper looper = handlerThread.getLooper();
        //子線程和子線程之間的通信
        mHandler = new Handler(looper);
        //EGl的綁定線程,對我們自己創(chuàng)建的EGl環(huán)境,都是在這個(gè)線程里面進(jìn)行
        mHandler.post(() -> {
            //創(chuàng)建我們的EGL環(huán)境(虛擬設(shè)備,EGL上下文 )
            mEglBase = new EGLBase(mContext, mWidth, mHeight, mInputSurface, mEglContext);
            //啟動(dòng)編碼器
            mMediaCodec.start();
            isStart = true;
        });
    }
    /**
     * textureId 紋理id
     * 調(diào)用一次,就有一個(gè)新的圖片需要編碼
     */
    public void encodeFrame(int textureId, long timesnap) {
        if (!isStart) {
            return;
        }
        //切換到子線程中編碼
        mHandler.post(() -> {
            //把圖像紋理畫到虛擬屏幕里面
            mEglBase.draw(textureId, timesnap);
            //此時(shí)我們需要從編碼器里面的輸出緩沖區(qū)獲取編碼以后的數(shù)據(jù)就可以了,
            getCodec(false);
        });
    }
    private void getCodec(boolean endOfStream) {
        if (endOfStream) {
            //表示停止錄制,此時(shí)我們不錄制了,需要給mediacoic 通知
            mMediaCodec.signalEndOfInputStream();
        }
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        //希望將已經(jīng)編碼完成的數(shù)據(jù)都獲取到,然后寫出到mp4文件中
        while (true) {
            //并不是傳給mediacodec一幀數(shù)據(jù)就表示可以編碼出一幀數(shù)據(jù),有可能需要好多幀數(shù)據(jù)才可以同時(shí)編碼出數(shù)據(jù)出來
            //輸出緩沖區(qū)
            //傳遞-1表示一直等到輸出緩沖區(qū)有一個(gè)編碼好的有效的數(shù)據(jù)以后才會(huì)繼續(xù)向下走,不然就會(huì)一直卡在127行,
            //10_000超時(shí)時(shí)間
            int status = mMediaCodec.dequeueOutputBuffer(bufferInfo, 10_000);
            if (status == MediaCodec.INFO_TRY_AGAIN_LATER) {
                //如果是停止,就繼續(xù)循環(huán),
                // 繼續(xù)循環(huán)就表示不會(huì)接收到新的等待編碼的圖像了
                //相當(dāng)于保證mediacodic中所有待編碼的數(shù)據(jù)都編碼完成
                // 標(biāo)記不是停止,我們退出,下一輪接收到更多的數(shù)據(jù)才來輸出編碼以后的數(shù)據(jù),我們就讓繼續(xù)走
                // 表示需要更多數(shù)據(jù)才可以編碼出圖像  false是繼續(xù)錄制,未來還有機(jī)會(huì)在調(diào)用getCodec
                if (!endOfStream) {
                    //結(jié)束錄制了
                    break;
                }
                //否則繼續(xù)
            } else if (status == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                //開始編碼,就會(huì)調(diào)用一次
                MediaFormat outputFormat = mMediaCodec.getOutputFormat();
                //配置封裝器,增加一路指定格式的媒體流
                index = mMediaMuxer.addTrack(outputFormat);
                //啟動(dòng)封裝器
                mMediaMuxer.start();
            } else if (status == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
                //忽略
            } else {
                //成功取出一個(gè)有效的輸出
                ByteBuffer outputBuffer = mMediaCodec.getOutputBuffer(status);
                if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
                    //如果獲取的ByteBuffer是配置信息,那么就不需要寫出到mp4文件中
                    bufferInfo.size = 0;
                }
                if (bufferInfo.size != 0) {
                    bufferInfo.presentationTimeUs = (long) (bufferInfo.presentationTimeUs / mSpeed);
                    //寫出到 mp4文件中
                    //根據(jù)偏移定位去獲取數(shù)據(jù),而不是從0開始
                    outputBuffer.position(bufferInfo.offset);
                    //設(shè)置可讀可寫的總長度
                    outputBuffer.limit(bufferInfo.offset + bufferInfo.size);
                    mMediaMuxer.writeSampleData(index, outputBuffer, bufferInfo);
                }
                //輸出緩沖區(qū)使用完畢了, 此時(shí)就可以回收了,讓mediacodec繼續(xù)使用
                mMediaCodec.releaseOutputBuffer(status, false);
                if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                    //結(jié)束了,
                    break;
                }
            }
        }
    }
    public void stop() {
        isStart = false;
        mHandler.post(() -> {
            getCodec(true);
            mMediaCodec.stop();
            mMediaCodec.release();
            mMediaCodec = null;
            mMediaMuxer.stop();
            mMediaMuxer.release();
            mMediaMuxer = null;
            mEglBase.release();
            mEglBase = null;
            mInputSurface = null;
            mHandler.getLooper().quitSafely();
            mHandler = null;
        });
    }
}

8.4 配置egl環(huán)境

/**
 * EGL配置 和錄制opengl的操作
 */
public class EGLBase {
    private final EGLSurface mEglSurface;
    private final ScreeFilter mScreeFilter;
    private EGLDisplay mEglDisplay;
    private EGLConfig mEglConfig;
    private EGLContext mEGLContext;
    /**
     * @param context
     * @param width
     * @param height
     * @param surface MediaCodec創(chuàng)建的surface, 我們需要將這個(gè)surface貼到虛擬屏幕里面
     */
    public EGLBase(Context context, int width, int height, Surface surface, EGLContext eglContext) {
        createEGL(eglContext);
        //把surface貼到EGLDisplay 虛擬屏幕里面
        int[] attrib_list = {
                //不需要配置什么屬性
                EGL14.EGL_NONE};
        //就是向mEglDisplay這個(gè)虛擬屏幕上面畫畫
        mEglSurface = EGL14.eglCreateWindowSurface(mEglDisplay, mEglConfig, surface, attrib_list, 0);
        //必須要綁定當(dāng)前線程的顯示上下文,不然就繪制不上去,這樣子之后操作的opelgl就是在這個(gè)虛擬屏幕上操作,讀和寫都是在同一個(gè)surface里面
        if (!EGL14.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEGLContext)) {
            throw new RuntimeException("eglMakeCurrent failed");
        }
        //向虛擬屏幕畫畫
        mScreeFilter = new ScreeFilter(context);
        mScreeFilter.onReady(width, height);
    }
    private void createEGL(EGLContext eglContext) {
        //創(chuàng)建虛擬顯示器
        mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
        if (mEglDisplay == EGL14.EGL_NO_DISPLAY) {
            throw new RuntimeException("eglGetDisplay failed");
        }
        int[] version = new int[2];
        //初始化虛擬設(shè)備
        if (!EGL14.eglInitialize(mEglDisplay, version, 0, version, 1)) {
            throw new RuntimeException("eglInitialize failed");
        }
        int[] attrib_list = new int[]{//rgba 紅綠藍(lán)透明度
                EGL14.EGL_RED_SIZE, 8, EGL14.EGL_GREEN_SIZE, 8, EGL14.EGL_BLUE_SIZE, 8, EGL14.EGL_ALPHA_SIZE, 8, EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,//和egl的版本有關(guān)系
                EGL14.EGL_NONE//這個(gè)很重要,一定要配置為NONE,表示配置結(jié)束了
        };
        EGLConfig[] configs = new EGLConfig[1];
        int[] num_config = new int[1];
        boolean eglChooseConfig = EGL14.eglChooseConfig(mEglDisplay, attrib_list, 0, configs, 0, configs.length, num_config, 0);
        if (!eglChooseConfig) {
            //如果配置失敗
            throw new IllegalArgumentException("eglChooseConfig failed");
        }
        mEglConfig = configs[0];
        int[] attriblist = {EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE};
        //創(chuàng)建EGL上下文
        //share_context 共享上下,傳遞繪制線程的(GLThread)EGL上下文,達(dá)到共享資源的目的
        mEGLContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig, eglContext, attriblist, 0);
        if (mEGLContext == null || mEGLContext == EGL14.EGL_NO_CONTEXT) {
            mEGLContext = null;
            throw new RuntimeException("createContex error !");
        }
    }
    /**
     * @param textureId 紋理id,代表一張圖片
     * @param timesnap  時(shí)間戳
     */
    public void draw(int textureId, long timesnap) {
        //必須要綁定當(dāng)前線程的顯示上下文,不然就繪制不上去,這樣子之后操作的opelgl就是在這個(gè)虛擬屏幕上操作,讀和寫都是在同一個(gè)surface里面
        //畫畫之前也必須要綁定
        if (!EGL14.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEGLContext)) {
            throw new RuntimeException("eglMakeCurrent failed");
        }
        //向虛擬屏幕畫畫
        mScreeFilter.onDrawFrame(textureId);
        //刷新eglSurface時(shí)間戳
        EGLExt.eglPresentationTimeANDROID(mEglDisplay, mEglSurface, timesnap);
        //交換數(shù)據(jù),EGL工作模式,雙緩存模式,內(nèi)部有兩個(gè)frameBuff,當(dāng)EGL將一個(gè)frame顯示到屏幕上以后,
        // 另一個(gè)frame就在后臺(tái)等待opengl進(jìn)行交換
        //也就是畫完一次,交換一次
        EGL14.eglSwapBuffers(mEglDisplay, mEglSurface);
    }
    public void release() {
        EGL14.eglDestroySurface(mEglDisplay, mEglSurface);
        EGL14.eglMakeCurrent(mEglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
        EGL14.eglDestroyContext(mEglDisplay, mEGLContext);
        EGL14.eglReleaseThread();
        EGL14.eglTerminate(mEglDisplay);
    }
}

8.5 配置shader

public class AbstractFilter {
    protected FloatBuffer mGLVertexBuffer;
    protected FloatBuffer mGLTextureBuffer;
    //頂點(diǎn)著色
    protected int mVertexShaderId;
    //片段著色
    protected int mFragmentShaderId;
    protected int mGLProgramId;
    /**
     * 頂點(diǎn)著色器
     * attribute vec4 position;
     * 賦值給gl_Position(頂點(diǎn))
     */
    protected int vPosition;
    /**
     * varying vec2 textureCoordinate;
     */
    protected int vCoord;
    /**
     * uniform mat4 vMatrix;
     */
    protected int vMatrix;
    /**
     * 片元著色器
     * Samlpe2D 擴(kuò)展 samplerExternalOES
     */
    protected int vTexture;
    protected int mOutputWidth;
    protected int mOutputHeight;
    public AbstractFilter(Context context, int vertexShaderId, int fragmentShaderId) {
        this.mVertexShaderId = vertexShaderId;
        this.mFragmentShaderId = fragmentShaderId;
        // 4個(gè)點(diǎn) x,y = 4*2 float 4字節(jié) 所以 4*2*4
        mGLVertexBuffer = ByteBuffer.allocateDirect(4 * 2 * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
        mGLVertexBuffer.clear();
        float[] VERTEX = {-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f};
        mGLVertexBuffer.put(VERTEX);
        mGLTextureBuffer = ByteBuffer.allocateDirect(4 * 2 * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
        mGLTextureBuffer.clear();
        float[] TEXTURE = {0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f};
        mGLTextureBuffer.put(TEXTURE);
        initilize(context);
        initCoordinate();
    }
    protected void initilize(Context context) {
        String vertexSharder = OpenGLUtils.readRawTextFile(context, mVertexShaderId);
        String framentShader = OpenGLUtils.readRawTextFile(context, mFragmentShaderId);
        mGLProgramId = OpenGLUtils.loadProgram(vertexSharder, framentShader);
        // 獲得著色器中的 attribute 變量 position 的索引值
        vPosition = GLES20.glGetAttribLocation(mGLProgramId, "vPosition");
        vCoord = GLES20.glGetAttribLocation(mGLProgramId, "vCoord");
        vMatrix = GLES20.glGetUniformLocation(mGLProgramId, "vMatrix");
        // 獲得Uniform變量的索引值
        vTexture = GLES20.glGetUniformLocation(mGLProgramId, "vTexture");
    }
    public void onReady(int width, int height) {
        mOutputWidth = width;
        mOutputHeight = height;
    }
    public void release() {
        GLES20.glDeleteProgram(mGLProgramId);
    }
    public int onDrawFrame(int textureId) {
        //設(shè)置顯示窗口
        GLES20.glViewport(0, 0, mOutputWidth, mOutputHeight);
        //使用著色器
        GLES20.glUseProgram(mGLProgramId);
        //傳遞坐標(biāo)
        mGLVertexBuffer.position(0);
        GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 0, mGLVertexBuffer);
        GLES20.glEnableVertexAttribArray(vPosition);
        mGLTextureBuffer.position(0);
        GLES20.glVertexAttribPointer(vCoord, 2, GLES20.GL_FLOAT, false, 0, mGLTextureBuffer);
        GLES20.glEnableVertexAttribArray(vCoord);
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        //綁定
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
        GLES20.glUniform1i(vTexture, 0);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
        //解綁
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
        return textureId;
    }
    //修改坐標(biāo)
    protected void initCoordinate() {
    }
}

到此這篇關(guān)于Android使用OpenGL和MediaCodec錄制的文章就介紹到這了,更多相關(guān)Android使用OpenGL和MediaCodec內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論