package com.laifeng.sopcastsdk.video;
import android.graphics.Bitmap;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import com.laifeng.sopcastsdk.camera.CameraData;
import com.laifeng.sopcastsdk.camera.CameraHolder;
import com.laifeng.sopcastsdk.entity.Watermark;
import com.laifeng.sopcastsdk.entity.WatermarkPosition;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
/**
* @Title: RenderScreen
* @Package com.laifeng.sopcastsdk.video
* @Description:
* @Author Jim
* @Date 16/9/14
* @Time 下午2:15
* @Version
*/
public class RenderScreen {
private final FloatBuffer mNormalVtxBuf = GlUtil.createVertexBuffer();
private final FloatBuffer mNormalTexCoordBuf = GlUtil.createTexCoordBuffer();
private final float[] mPosMtx = GlUtil.createIdentityMtx();
private int mFboTexId;
private int mProgram = -1;
private int maPositionHandle = -1;
private int maTexCoordHandle = -1;
private int muPosMtxHandle = -1;
private int muSamplerHandle = -1;
private int mScreenW = -1;
private int mScreenH = -1;
private FloatBuffer mCameraTexCoordBuffer;
private Bitmap mWatermarkImg;
private Watermark mWatermark;
private FloatBuffer mWatermarkVertexBuffer;
private int mWatermarkTextureId = -1;
private float mWatermarkRatio = 1.0f;
public RenderScreen(int id) {
mFboTexId = id;
initGL();
}
public void setSreenSize(int width, int height) {
mScreenW = width;
mScreenH = height;
initCameraTexCoordBuffer();
}
public void setTextureId(int textureId) {
mFboTexId = textureId;
}
public void setVideoSize(int width, int height) {
mWatermarkRatio = mScreenW / ((float)width);
if(mWatermark != null) {
initWatermarkVertexBuffer();
}
}
private void initCameraTexCoordBuffer() {
int cameraWidth, cameraHeight;
CameraData cameraData = CameraHolder.instance().getCameraData();
int width = cameraData.cameraWidth;
int height = cameraData.cameraHeight;
if(CameraHolder.instance().isLandscape()) {
cameraWidth = Math.max(width, height);
cameraHeight = Math.min(width, height);
} else {
cameraWidth = Math.min(width, height);
cameraHeight = Math.max(width, height);
}
float hRatio = mScreenW / ((float)cameraWidth);
float vRatio = mScreenH / ((float)cameraHeight);
float ratio;
if(hRatio > vRatio) {
ratio = mScreenH / (cameraHeight * hRatio);
final float vtx[] = {
//UV
0f, 0.5f + ratio/2,
0f, 0.5f - ratio/2,
1f, 0.5f + ratio/2,
1f, 0.5f - ratio/2,
};
ByteBuffer bb = ByteBuffer.allocateDirect(4 * vtx.length);
bb.order(ByteOrder.nativeOrder());
mCameraTexCoordBuffer = bb.asFloatBuffer();
mCameraTexCoordBuffer.put(vtx);
mCameraTexCoordBuffer.position(0);
} else {
ratio = mScreenW/ (cameraWidth * vRatio);
final float vtx[] = {
//UV
0.5f - ratio/2, 1f,
0.5f - ratio/2, 0f,
0.5f + ratio/2, 1f,
0.5f + ratio/2, 0f,
};
ByteBuffer bb = ByteBuffer.allocateDirect(4 * vtx.length);
bb.order(ByteOrder.nativeOrder());
mCameraTexCoordBuffer = bb.asFloatBuffer();
mCameraTexCoordBuffer.put(vtx);
mCameraTexCoordBuffer.position(0);
}
}
public void setWatermark(Watermark watermark) {
mWatermark = watermark;
mWatermarkImg = watermark.markImg;
initWatermarkVertexBuffer();
}
private void initWatermarkVertexBuffer() {
if (mScreenW <= 0 || mScreenH <= 0) {
return;
}
int width = (int) (mWatermark.width*mWatermarkRatio);
int height = (int) (mWatermark.height*mWatermarkRatio);
int vMargin = (int) (mWatermark.vMargin*mWatermarkRatio);
int hMargin = (int) (mWatermark.hMargin*mWatermarkRatio);
boolean isTop, isRight;
if(mWatermark.orientation == WatermarkPosition.WATERMARK_ORIENTATION_TOP_LEFT
|| mWatermark.orientation == WatermarkPosition.WATERMARK_ORIENTATION_TOP_RIGHT) {
isTop = true;
} else {
isTop = false;
}
if(mWatermark.orientation == WatermarkPosition.WATERMARK_ORIENTATION_TOP_RIGHT
|| mWatermark.orientation == WatermarkPosition.WATERMARK_ORIENTATION_BOTTOM_RIGHT) {
isRight = true;
} else {
isRight = false;
}
float leftX = (mScreenW/2.0f - hMargin - width)/(mScreenW/2.0f);
float rightX = (mScreenW/2.0f - hMargin)/(mScreenW/2.0f);
float topY = (mScreenH/2.0f - vMargin)/(mScreenH/2.0f);
float bottomY = (mScreenH/2.0f - vMargin - height)/(mScreenH/2.0f);
float temp;
if(!isRight) {
temp = leftX;
leftX = -rightX;
rightX = -temp;
}
if(!isTop) {
temp = topY;
topY = -bottomY;
bottomY = -temp;
}
final float watermarkCoords[]= {
leftX, bottomY, 0.0f,
leftX, topY, 0.0f,
rightX, bottomY, 0.0f,
rightX, topY, 0.0f
};
ByteBuffer bb = ByteBuffer.allocateDirect(watermarkCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
mWatermarkVertexBuffer = bb.asFloatBuffer();
mWatermarkVertexBuffer.put(watermarkCoords);
mWatermarkVertexBuffer.position(0);
}
public void draw() {
if (mScreenW <= 0 || mScreenH <= 0) {
return;
}
GlUtil.checkGlError("draw_S");
GLES20.glViewport(0, 0, mScreenW, mScreenH);
GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1f);
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glUseProgram(mProgram);
mNormalVtxBuf.position(0);
GLES20.glVertexAttribPointer(maPositionHandle,
3, GLES20.GL_FLOAT, false, 4 * 3, mNormalVtxBuf);
GLES20.glEnableVertexAttribArray(maPositionHandle);
mCameraTexCoordBuffer.position(0);
GLES20.glVertexAttribPointer(maTexCoordHandle,
2, GLES20.GL_FLOAT, false, 4 * 2, mCameraTexCoordBuffer);
GLES20.glEnableVertexAttribArray(maTexCoordHandle);
GLES20.glUniformMatrix4fv(muPosMtxHandle, 1, false, mPosMtx, 0);
GLES20.glUniform1i(muSamplerHandle, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mFboTexId);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
//绘制纹理
drawWatermark();
GlUtil.checkGlError("draw_E");
}
private void drawWatermark() {
if(mWatermarkImg == null) {
return;
}
mWatermarkVertexBuffer.position(0);
GLES20.glVertexAttribPointer(maPositionHandle,
3, GLES20.GL_FLOAT, false, 4 * 3, mWatermarkVertexBuffer);
GLES20.glEnableVertexAttribArray(maPositionHandle);
mNormalTexCoordBuf.position(0);
GLES20.glVertexAttribPointer(maTexCoordHandle,
2, GLES20.GL_FLOAT, false, 4 * 2, mNormalTexCoordBuf);
GLES20.glEnableVertexAttribArray(maTexCoordHandle);
if(mWatermarkTextureId == -1) {
int[] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, mWatermarkImg, 0);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
GLES20.GL_CLAMP_TO_EDGE);
mWatermarkTextureId = textures[0];
}
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mWatermarkTextureId);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
GLES20.glDisable(GLES20.GL_BLEND);
}
private void initGL() {
GlUtil.checkGlError("initGL_S");
final String vertexShader =
//
"attribute vec4 position;\n" +
"attribute vec4 inputTextureCoordinate;\n" +
"uniform mat4 uPosMtx;\n" +
"varying vec2 textureCoordinate;\n" +
"void main() {\n" +
" gl_Position = uPosMtx * position;\n" +
" textureCoordinate = inputTextureCoordinate.xy;\n" +
"}\n";
final String fragmentShader =
//
"precision mediump float;\n" +
"uniform sampler2D uSampler;\n" +
"varying vec2 textureCoordinate;\n" +
"void main() {\n" +
" gl_FragColor = texture2D(uSampler, textureCoordinate);\n" +
"}\n";
mProgram = GlUtil.createProgram(vertexShader, fragmentShader);
maPositionHandle = GLES20.glGetAttribLocation(mProgram, "position");
maTexCoordHandle = GLES20.glGetAttribLocation(mProgram, "inputTextureCoordinate");
muPosMtxHandle = GLES20.glGetUniformLocation(mProgram, "uPosMtx");
muSamplerHandle = GLES20.glGetUniformLocation(mProgram, "uSampler");
GlUtil.checkGlError("initGL_E");
}
}