Android通過openGL實現視頻貼紙功能

Android通過openGL實現視頻貼紙功能

GLSL代碼

1.vertex代碼,文件vertex_filter_stricker.glsl

attribute vec2 inputTextureCoordinate; //紋理座標
attribute vec4 position;// 頂點座標
varying   vec2 textureCoordinate;//紋理座標點變換後輸出

void main() {
    gl_Position = position;
    textureCoordinate = inputTextureCoordinate;
}

2.fragment代碼,文件fragment_filter_stricker.glsl

//設置精度
precision highp float;
varying highp vec2 textureCoordinate;
uniform sampler2D videoTexture;
uniform sampler2D uImageTexture;
uniform vec4 imageRect;

void main(){
    lowp vec4 c1 = texture2D(videoTexture, textureCoordinate);
    lowp vec2 vCamTextureCoord2 = vec2(textureCoordinate.x, 1.0-textureCoordinate.y);
    if (vCamTextureCoord2.x>imageRect.r && vCamTextureCoord2.x<imageRect.b && vCamTextureCoord2.y>imageRect.g && vCamTextureCoord2.y<imageRect.a)
    {
        vec2 imagexy = vec2((vCamTextureCoord2.x-imageRect.r)/(imageRect.b-imageRect.r), (vCamTextureCoord2.y-imageRect.g)/(imageRect.a-imageRect.g));
        lowp vec4 c2 = texture2D(uImageTexture, imagexy);
        lowp vec4 outputColor = c2+c1*c1.a*(1.0-c2.a);
        outputColor.a = 1.0;
        gl_FragColor = outputColor;
    } else {
        gl_FragColor = c1;
    }
}

Java代碼

package com.dong.opencamera.core.filter.impl;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.RectF;
import android.opengl.GLES20;

import com.dong.opencamera.core.filter.IVideoFilter;
import com.dong.opencamera.utils.GLHelper;

import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

/**
 * @author : liaojidong
 * @date : 2020-01-13 15:00
 * @desc :
 */
public class StickerFilter implements IVideoFilter {
    // number of coordinates per vertex in this array
    private static final int COORDS_PER_VERTEX = 3;
    private static final short[] ORDERS = {
            0, 1, 2, // 左下角三角形
            2, 3, 0  // 右上角三角形
    };

    private Context mContext;
    private volatile boolean isInit = false;
    private Bitmap mStickerBitmap;
    private int mProgram;
    private int glImageTextureLoc;
    private int glImageRectLoc;
    private int videoTextureLoc;
    private int uPosLocation;
    private int aTexLocation;

    protected int imageTexture;
    private RectF imageRectF = new RectF();

    private int width;
    private int height;

    public StickerFilter(Context context,
                         Bitmap stickerBitmap) {
        this.mStickerBitmap = stickerBitmap;
        this.mContext = context;
    }

    @Override
    public void onFilterChanged(int surfaceWidth, int surfaceHeight) {
        this.width = surfaceWidth;
        this.height = surfaceHeight;
    }

    private void init() {
        if (isInit) return;

        mProgram = GLHelper.createProgram(mContext,
                "vertex_filter_stricker.glsl",
                "fragment_filter_stricker.glsl");
        // 將程序添加到OpenGL ES環境
        GLES20.glUseProgram(mProgram);

        // 獲取頂點着色器的位置的句柄
        uPosLocation = GLES20.glGetAttribLocation(mProgram, "position");
        aTexLocation = GLES20.glGetAttribLocation(mProgram, "inputTextureCoordinate");

        videoTextureLoc = GLES20.glGetUniformLocation(mProgram, "videoTexture");
        glImageRectLoc = GLES20.glGetUniformLocation(mProgram, "imageRect");
        glImageTextureLoc = GLES20.glGetUniformLocation(mProgram, "uImageTexture");

        imageTexture = GLHelper.loadTexture(mContext, mStickerBitmap);


        isInit = true;
    }

    public void setStickerLoc(int x, int y) {
        imageRectF.left = (float) ((x * 1.0) / (width * 1.0));
        imageRectF.right = (float) (imageRectF.left + ((mStickerBitmap.getWidth() * 1.0) / (width * 1.0)));
        imageRectF.top = (float) ((y * 1.0) / (height * 1.0));
        imageRectF.bottom = (float) (imageRectF.top + ((mStickerBitmap.getHeight() * 1.0) / (height * 1.0)));
    }

    @Override
    public void onDraw(int inputTexture,
                       int targetFrameBuffer,
                       FloatBuffer vertexPosBuffer,
                       FloatBuffer texturePosBuffer,
                       ShortBuffer order) {
        init();
        setStickerLoc(100, 100);
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, targetFrameBuffer);
        GLES20.glUseProgram(mProgram);

        // Set the active texture unit to texture unit 0.
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        // Bind the texture to this unit 0.
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, inputTexture);
        // Tell the texture uniform sampler to use this texture in the shader by
        // telling it to read from texture unit 0.
        GLES20.glUniform1i(videoTextureLoc, 0);

        // Set the active texture unit to texture unit 1.
        GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
        // Bind the texture to this unit 1.
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, imageTexture);
        // Tell the texture uniform sampler to use this texture in the shader by
        // telling it to read from texture unit 1.
        GLES20.glUniform1i(glImageTextureLoc, 1);

        // 將數據傳遞到着色器中
        GLES20.glVertexAttribPointer(uPosLocation, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, vertexPosBuffer);
        GLES20.glVertexAttribPointer(aTexLocation, 2, GLES20.GL_FLOAT, false, 0, texturePosBuffer);

        GLES20.glUniform4f(glImageRectLoc, imageRectF.left, imageRectF.top, imageRectF.right, imageRectF.bottom);

        // 啓用頂點位置的句柄
        GLES20.glEnableVertexAttribArray(uPosLocation);
        GLES20.glEnableVertexAttribArray(aTexLocation);

        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
        GLES20.glDrawElements(GLES20.GL_TRIANGLES, ORDERS.length, GLES20.GL_UNSIGNED_SHORT, order);

        GLES20.glFinish();
        GLES20.glDisableVertexAttribArray(uPosLocation);
        GLES20.glDisableVertexAttribArray(aTexLocation);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
        GLES20.glUseProgram(0);
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
    }
}

效果如下圖所示:
在這裏插入圖片描述

總結

貼紙的原理本質就是在繪製的時候判斷當前位置是應該繪製視頻還是應該繪製貼紙。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章