预览摄像头画面-解决小问题
程序员文章站
2022-03-16 15:19:21
GCamerapackage com.example.glivepush.camera;import android.content.Context;import android.graphics.ImageFormat;import android.graphics.SurfaceTexture;import android.hardware.Camera;import com.example.glivepush.util.DisplayUtil;import java.io.IO...
GCamera
package com.example.glivepush.camera;
import android.content.Context;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import com.example.glivepush.util.DisplayUtil;
import java.io.IOException;
import java.util.List;
public class GCamera {
private Camera camera;
/*********************************** 解决拉伸问题-START *****************************/
private int width;
private int height;
public GCamera(Context context) {
this.width = DisplayUtil.getScreenWidth(context);
this.height = DisplayUtil.getScreenHeight(context);
}
/*********************************** 解决拉伸问题-END *****************************/
private SurfaceTexture surfaceTexture;
public void initCamera(SurfaceTexture surfaceTexture,int cameraId){
this.surfaceTexture = surfaceTexture;
setCameraParm(cameraId);
}
//预览
private void setCameraParm(int cameraId){
try {
camera = Camera.open(cameraId);
camera.setPreviewTexture(surfaceTexture);
Camera.Parameters parameters = camera.getParameters();
parameters.setFlashMode("off");
parameters.setPictureFormat(ImageFormat.NV21);
/*********************************** 解决拉伸问题-START *****************************/
Camera.Size size = getFitSize(parameters.getSupportedPictureSizes());
parameters.setPictureSize(size.width, size.height);
//预览大小
size = getFitSize(parameters.getSupportedPreviewSizes());
parameters.setPreviewSize(size.width, size.height);
/*********************************** 解决拉伸问题-END *****************************/
camera.setParameters(parameters);
camera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
public void stopPreview(){
if(camera != null){
camera.startPreview();
camera.release();
camera = null;
}
}
public void changeCamera(int cameraId){
if(camera != null){
stopPreview();
}
setCameraParm(cameraId);
}
/*********************************** 解决拉伸问题-START *****************************/
private Camera.Size getFitSize(List<Camera.Size> sizes) {
if(width < height) {
int t = height;
height = width;
width = t;
}
for(Camera.Size size : sizes) {
if(1.0f * size.width / size.height == 1.0f * width / height) {
return size;
}
}
return sizes.get(0);
}
/*********************************** 解决拉伸问题-END *****************************/
}
GCameraRender
package com.example.glivepush.camera;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.opengl.Matrix;
import android.util.Log;
import com.example.glivepush.R;
import com.example.glivepush.egl.GEGLSurfaceView;
import com.example.glivepush.egl.GShaderUtil;
import com.example.glivepush.util.DisplayUtil;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
public class GCameraRender implements GEGLSurfaceView.GGLRender , SurfaceTexture.OnFrameAvailableListener {
private Context context;
private FloatBuffer vertexBuffer;
private FloatBuffer fragmentBuffer;
private int program;
private int vPosition;
private int fPosition;
private int vboId;
private int fboId;
private int fboTextureid;
private int cameraTextureid;
/*********************************** 解决横屏问题-START *********************************/
private int screenWidth;
private int screenHeight;
private int width;
private int height;
/*********************************** 解决横屏问题-END *********************************/
private GCameraFboRender gCameraFboRender;
private SurfaceTexture surfaceTexture;
private OnSurfaceCreateListener onSurfaceCreateListener;
public void setOnSurfaceCreateListener(OnSurfaceCreateListener onSurfaceCreateListener) {
this.onSurfaceCreateListener = onSurfaceCreateListener;
}
/*********************************** 矩阵旋转-START *************************************/
private int umatrix;
private float[] matrix = new float[16];
/*********************************** 矩阵旋转-END ***************************************/
private final float[] vertexData = {
-1f, -1f,
1f, -1f,
-1f, 1f,
1f, 1f
};
private final float[] fragmentData = {
0f, 1f,
1f, 1f,
0f, 0f,
1f, 0f
};
public GCameraRender(Context context) {
this.context = context;
/*********************************** 解决横屏问题-START *********************************/
this.screenWidth = DisplayUtil.getScreenWidth(context);
this.screenHeight = DisplayUtil.getScreenHeight(context);
/*********************************** 解决横屏问题-END *********************************/
gCameraFboRender = new GCameraFboRender(context);
vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(vertexData);
vertexBuffer.position(0);
fragmentBuffer = ByteBuffer.allocateDirect(fragmentData.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(fragmentData);
fragmentBuffer.position(0);
/*********************************** 矩阵旋转-START *********************************/
//初始化矩阵
/*********************************** 矩阵旋转-END ************************************/
}
@Override
public void onSurfaceCreated() {
gCameraFboRender.onCreate();
//获取着色器属性
String vertexSource = GShaderUtil.getRawResource(context, R.raw.vertex_shader);
String fragmentSource = GShaderUtil.getRawResource(context, R.raw.fragment_shader);
program = GShaderUtil.createProgram(vertexSource, fragmentSource);
//顶点坐标
vPosition = GLES20.glGetAttribLocation(program, "v_Position");
//纹理坐标
fPosition = GLES20.glGetAttribLocation(program, "f_Position");
/*********************************** 矩阵旋转-START *************************************/
//加载矩阵
umatrix = GLES20.glGetUniformLocation(program,"u_Matrix");
/*********************************** 矩阵旋转-START *************************************/
int [] vbos = new int[1];
GLES20.glGenBuffers(1, vbos, 0);
vboId = vbos[0];
//绑定
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboId);
//分配内存
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertexData.length*4 + fragmentData.length*4,
null,GLES20. GL_STATIC_DRAW);
//缓存到显存
GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, 0, vertexData.length * 4, vertexBuffer);
GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, vertexData.length * 4, fragmentData.length * 4,
fragmentBuffer);
//解绑
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
//fbo
int [] fbos = new int[1];
GLES20.glGenBuffers(1, fbos, 0);
fboId = fbos[0];
//绑定
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId);
//生成纹理
int[] textureIds = new int[1];
GLES20.glGenTextures(1, textureIds, 0);
fboTextureid = textureIds[0];
//绑定
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fboTextureid);
//设置环绕过滤方法
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
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);
/*********************************** 解决横屏问题-START *********************************/
//设置FBO分配内存大小
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, screenWidth, screenHeight, 0,
GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
/*********************************** 解决横屏问题-END *********************************/
//把纹理绑定到FBO
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
GLES20.GL_TEXTURE_2D, fboTextureid, 0);
//检查FBO绑定是否成功
if(GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER) != GLES20.GL_FRAMEBUFFER_COMPLETE){
Log.e("godv", "fbo error");
}else {
Log.e("godv", "fbo success");
}
//解绑纹理
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
//解绑
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
//生成摄像头纹理
int[] textureIdsoes = new int[1];
GLES20.glGenTextures(1, textureIdsoes, 0);
cameraTextureid = textureIdsoes[0];
//绑定扩展纹理
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, cameraTextureid);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
//摄像头id
surfaceTexture = new SurfaceTexture(cameraTextureid);
//监听
surfaceTexture.setOnFrameAvailableListener(this);
if(onSurfaceCreateListener !=null){
onSurfaceCreateListener.onSurfaceCreate(surfaceTexture);
}
//解绑纹理
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
}
/*********************************** 矩阵旋转-START *************************************/
//重置矩阵
public void resetMatrix(){
Matrix.setIdentityM(matrix, 0);
}
//设置角度
public void setAngle(float angle ,float x, float y,float z){
Matrix.rotateM(matrix, 0, angle, x, y, z);
}
/*********************************** 矩阵旋转-END *************************************/
@Override
public void onSurfaceChanged(int width, int height) {
// gCameraFboRender.onChange(width, height);
// GLES20.glViewport(0,0,width,height);
/*********************************** 解决横屏问题-START *****************************/
this.width = width;
this.height = height;
/*********************************** 解决横屏问题-END ********************************/
}
@Override
public void onDrawFrame() {
surfaceTexture.updateTexImage();
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glClearColor(1f,0f, 0f, 1f);
GLES20.glUseProgram(program);
/*********************************** 矩阵旋转-START *********************************/
//设置屏幕大小
GLES20.glViewport(0,0,screenWidth,screenHeight);
//使用
GLES20.glUniformMatrix4fv(umatrix, 1, false, matrix, 0);
/*********************************** 矩阵旋转-END ***********************************/
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboId);
GLES20.glEnableVertexAttribArray(vPosition);
GLES20.glVertexAttribPointer(vPosition, 2, GLES20.GL_FLOAT, false, 8,
0);
GLES20.glEnableVertexAttribArray(fPosition);
GLES20.glVertexAttribPointer(fPosition, 2, GLES20.GL_FLOAT, false, 8,
vertexData.length * 4);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
gCameraFboRender.onChange(width, height);
gCameraFboRender.onDraw(fboTextureid);
}
//有数据回调
@Override
public void onFrameAvailable(SurfaceTexture surfaceTexture) {
}
public interface OnSurfaceCreateListener{
void onSurfaceCreate(SurfaceTexture surfaceTexture);
}
}
GCameraView
package com.example.glivepush.camera;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.util.AttributeSet;
import android.view.Surface;
import android.view.WindowManager;
import com.example.glivepush.egl.GEGLSurfaceView;
public class GCameraView extends GEGLSurfaceView {
private GCameraRender gCameraRender;
private GCamera gCamera;
private int cameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
public GCameraView(Context context) {
this(context,null);
}
public GCameraView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public GCameraView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
gCameraRender = new GCameraRender(context);
gCamera = new GCamera(context);
setRender(gCameraRender);
/*********************************** 旋转角度-START *************************************/
//调用获取旋转角度
previewAngle(context);
/*********************************** 旋转角度-END *************************************/
gCameraRender.setOnSurfaceCreateListener(new GCameraRender.OnSurfaceCreateListener() {
@Override
public void onSurfaceCreate(SurfaceTexture surfaceTexture) {
gCamera.initCamera(surfaceTexture, cameraId);
}
});
}
public void onDestory(){
if(gCamera != null){
gCamera.stopPreview();
}
}
/*********************************** 旋转角度-START *************************************/
public void previewAngle(Context context){
// 获取activity旋转角度
int angle = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay().getRotation();
gCameraRender.resetMatrix();
switch (angle){
case Surface.ROTATION_0:
if(cameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
gCameraRender.setAngle(90, 0, 0, 1);
gCameraRender.setAngle(180, 1, 0, 0);
} else {
gCameraRender.setAngle(90f, 0f, 0f, 1f);
}
break;
case Surface.ROTATION_90:
if(cameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
gCameraRender.setAngle(180, 0, 0, 1);
gCameraRender.setAngle(180, 0, 1, 0);
} else {
gCameraRender.setAngle(90f, 0f, 0f, 1f);
}
break;
case Surface.ROTATION_180:
if(cameraId == Camera.CameraInfo.CAMERA_FACING_BACK)
{
gCameraRender.setAngle(90f, 0.0f, 0f, 1f);
gCameraRender.setAngle(180f, 0.0f, 1f, 0f);
} else {
gCameraRender.setAngle(-90, 0f, 0f, 1f);
}
break;
case Surface.ROTATION_270:
if(cameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
gCameraRender.setAngle(180f, 0.0f, 1f, 0f);
} else {
gCameraRender.setAngle(0f, 0f, 0f, 1f);
}
break;
}
}
/*********************************** 旋转角度-END *************************************/
}
CameraActivity
package com.example.glivepush;
import android.content.res.Configuration;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.example.glivepush.camera.GCameraView;
public class CameraActivity extends AppCompatActivity {
private GCameraView gCameraView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
gCameraView = findViewById(R.id.cameraView);
}
@Override
protected void onDestroy() {
super.onDestroy();
gCameraView.onDestory();
}
/*********************************** 解决横屏问题-START *****************************/
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
gCameraView.previewAngle(this);
}
/*********************************** 解决横屏问题-END *****************************/
}
本文地址:https://blog.csdn.net/we1less/article/details/110294899