package com.android.example.cameraappxjava;
import android.Manifest;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaPlayer;
import android.net.Uri;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.SystemClock;
import android.provider.MediaStore;
import android.util.Log;
import android.util.Size;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.widget.Button;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import com.android.example.cameraappxjava.util.CameraRenderer;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "camera2api";
private static final int REQUEST_CAMERA_PERMISSION = 100;
private TextureView textureView;
private GLSurfaceView glSurfaceView;
private Button captureButton;
private CameraDevice cameraDevice;
private CameraCaptureSession cameraCaptureSession;
private CaptureRequest.Builder captureRequestBuilder;
private String cameraId;
private Handler backgroundHandler;
private boolean isSessionClosed;
private HandlerThread backgroundThread;
private ImageReader imageReader;
private boolean isTextureAvailable = false; // 跟踪Surface状态
private CameraManager manager;
private volatile boolean isCapturing = false;
private StreamConfigurationMap map;
private long lastClickTime = 0;
private static final long MIN_CLICK_INTERVAL = 1000; // 最小点击间隔1秒
private File file;
private ContentResolver resolver;
private ContentValues values;
private Uri imageUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate ——————————————————————");
captureButton = findViewById(R.id.btnCapture);
// textureView = findViewById(R.id.textureView);
glSurfaceView = findViewById(R.id.glsurfaceView);
glSurfaceView.setEGLContextClientVersion(3); // 使用 OpenGL ES 3.0
glSurfaceView.setRenderer(new CameraRenderer());
//初始化相机参数
initCamera();
//设置预览监听
glSurfaceView
textureView.setSurfaceTextureListener(surfaceTextureListener);
//设置拍照预监听
captureButton.setOnClickListener(v -> {//防止 连点抛出异常
long currentTime = SystemClock.elapsedRealtime();
if (currentTime - lastClickTime > MIN_CLICK_INTERVAL) {
lastClickTime = currentTime;
takePicture();
} else {
Log.d(TAG, "点击过快,已忽略");
}
});
}
@Override
protected void onResume() {
Log.d(TAG, "onResume —————————————————————— ");
Log.d(TAG, Log.getStackTraceString(new Throwable()));
super.onResume();
glSurfaceView.onResume(); // 必须添加
// 检查相机权限
// ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA):用于检测this(当前应用)是否有Manifest.permission.CAMERA权限
//有则返回PackageManager.PERMISSION_GRANTED(有权限),没有则返回PackageManager.PERMISSION_DENIED(无权限)
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "没有相机权限——>开始请求相机权限");
//ActivityCompat.requestPermissions():请求权限的方法
//this:当前应用
//new String[]{权限1,权限2,...}:请求的权限集合
//code:对应编码名,发送请求后会调用回调函数 onRequestPermissionsResult(),该回调的第一个参数就是这个code,用于给我们做请求权限后的自定义操作。
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
}
//注意:以上的权限请求是异步操作
startBackgroundThread();
// 如果Surface已经可用,重新打开相机
if (textureView.isAvailable()) {
openCamera();
}
}
@Override
protected void onPause() {
super.onPause();
Log.d(TAG, "onPause ——————————————————————");
glSurfaceView.onPause(); // 必须添加
// 1. 仅在“非拍照中”且“会话存在”时,停止预览的重复请求(避免授权时资源被清)
if (!isCapturing && cameraCaptureSession != null) {
try {
// 停止预览的重复请求(暂停预览画面),但不关闭会话和相机设备
cameraCaptureSession.stopRepeating();
Log.d(TAG, "onPause: 暂停预览重复请求(核心资源未释放)");
} catch (CameraAccessException e) {
Log.e(TAG, "onPause: 停止预览失败", e);
}
// 2. 拍照中时,延迟处理(避免中断拍照流程)
if (isCapturing) {
Log.w(TAG, "onPause: 拍照中,暂不处理预览暂停");
new Handler().postDelayed(() -> {
if (!isCapturing && cameraCaptureSession != null) {
try {
cameraCaptureSession.stopRepeating();
Log.d(TAG, "onPause: 拍照完成后,暂停预览");
} catch (CameraAccessException e) {
Log.e(TAG, "onPause: 延迟停止预览失败", e);
}
}
}, 1000);
}
}
}
@Override
protected void onStop() {
super.onStop();
Log.d(TAG, "onStop: Activity 完全不可见(如按Home键),释放核心资源");
// 1. 检查是否正在销毁(如果是销毁,交给 onDestroy 处理,避免重复释放)
if (isFinishing()) {
Log.d(TAG, "onStop: Activity 正在销毁,核心资源由 onDestroy 处理");
return;
}
// 2. 释放相机核心资源(会话、设备、ImageReader),但保留后台线程(onResume 可快速恢复)
if (cameraCaptureSession != null) {
cameraCaptureSession.close();
cameraCaptureSession = null;
Log.d(TAG, "onStop: 关闭 CameraCaptureSession");
}
if (cameraDevice != null) {
cameraDevice.close();
cameraDevice = null;
Log.d(TAG, "onStop: 关闭 CameraDevice");
}
if (imageReader != null) {
imageReader.close();
imageReader = null;
Log.d(TAG, "onStop: 关闭 ImageReader");
}
isSessionClosed = true;
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy: Activity 彻底销毁,释放所有资源");
// 1. 释放相机相关资源(防止内存泄漏)
if (cameraCaptureSession != null) {
cameraCaptureSession.close();
cameraCaptureSession = null;
}
if (cameraDevice != null) {
cameraDevice.close();
cameraDevice = null;
}
if (imageReader != null) {
imageReader.close();
imageReader = null;
}
// 2. 停止后台线程(彻底销毁,避免线程泄漏)
stopBackgroundThread();
// 3. 置空所有引用(帮助 GC 回收)
textureView = null;
captureButton = null;
manager = null;
resolver = null;
values = null;
imageUri = null;
backgroundHandler = null;
backgroundThread = null;
Log.d(TAG, "onDestroy: 所有资源释放完成");
}
private final TextureView.SurfaceTextureListener surfaceTextureListener = new TextureView.SurfaceTextureListener() {
//触发时机:SurfaceTexture 初始化后
@Override
public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
isTextureAvailable = true; // 设置可用标志
Log.d(TAG, "Surface就绪,触发相机初始化");
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
openCamera();
}
}
@Override
public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {
Log.d(TAG, "onSurfaceTextureSizeChanged: " + width + "x" + height);
}
@Override
public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
Log.d(TAG, "onSurfaceTextureDestroyed");
isTextureAvailable = false;
if (cameraCaptureSession != null) {
try {
cameraCaptureSession.stopRepeating();
} catch (CameraAccessException e) {
Log.e(TAG, "停止预览失败", e);
}
}
return true;
}
@Override
public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
}
};
private void initCamera() {
Log.d(TAG, "initCamera: 初始化相机配置");
try {
//1.初始化CameraManager,获取相机配置map
manager = (CameraManager) getSystemService(CAMERA_SERVICE);
cameraId = manager.getCameraIdList()[0];
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (map == null) {
Log.e(TAG, "错误: StreamConfigurationMap为空!!");
}
//2.图片保存参数配置
resolver = getContentResolver();
values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, "pic_" + System.currentTimeMillis() + ".jpg");
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
} catch (CameraAccessException e) {
Log.e(TAG, "相机访问异常: " + e.getMessage());
} catch (NullPointerException e) {
Log.e(TAG, "NPE: " + e.getMessage());
}
}
private Size chooseOptimalSize(Size[] choices, int width, int height) {
List<Size> bigEnough = new ArrayList<>();
for (Size option : choices) {
float ratio = (float) option.getWidth() / option.getHeight();
float viewRatio = (float) width / height;
if (Math.abs(ratio - viewRatio) <= 0.1 &&
option.getWidth() <= width &&
option.getHeight() <= height) {
bigEnough.add(option);
}
}
if (!bigEnough.isEmpty()) {
return Collections.max(bigEnough, new CompareSizesByArea());
}
Log.w(TAG, "未找到完美匹配尺寸,使用默认");
return choices[0];
}
static class CompareSizesByArea implements Comparator<Size> {
@Override
public int compare(Size lhs, Size rhs) {
return Long.signum((long) lhs.getWidth() * lhs.getHeight() - (long) rhs.getWidth() * rhs.getHeight());
}
}
private void openCamera() {
if (!isTextureAvailable || textureView.getSurfaceTexture() == null) { // 检查Surface是否可用
Log.w(TAG, "Surface不可用,延迟打开相机,100ms后重试");
backgroundHandler.postDelayed(this::openCamera, 10000);
return;
}
Log.d(TAG, "openCamera: 尝试打开相机");
try {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "1.打开相机: " + cameraId);
manager.openCamera(cameraId, stateCallback, backgroundHandler);
} else {
Log.w(TAG, "相机权限未授予");
}
} catch (CameraAccessException e) {
Log.e(TAG, "打开相机失败: " + e.getMessage());
} catch (SecurityException e) {
Log.e(TAG, "安全异常: " + e.getMessage());
}
}
private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice camera) {
Log.i(TAG, "相机已打开");
cameraDevice = camera;
Log.i(TAG, "2.1 开始配置预览流");
createCameraPreviewSession();
}
@Override
public void onDisconnected(@NonNull CameraDevice camera) {
Log.w(TAG, "相机断开连接");
cameraDevice.close();
}
@Override
public void onError(@NonNull CameraDevice camera, int error) {
Log.e(TAG, "相机错误: " + error);
cameraDevice.close();
cameraDevice = null;
}
};
//2.1 开始配置预览流
private void createCameraPreviewSession() {
if (cameraDevice == null || !isTextureAvailable) { // 双重检查
Log.e(TAG, "创建预览会话失败: 相机或Surface不可用");
return;
}
try {
//1.1 配置预览尺寸
// Size previewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class), textureView.getWidth(), textureView.getHeight());
// Log.i(TAG, "选择预览尺寸: " + previewSize.getWidth() + "x" + previewSize.getHeight());
//
// //1.2 配置预览Surface
// SurfaceTexture previewTexture = textureView.getSurfaceTexture();
// previewTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
// Surface previewSurface = new Surface(previewTexture);
// GLSurfaceView 配置
Surface glSurface = glSurfaceView.getHolder().getSurface();
glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
// 创建会话时使用 GLSurfaceView 的 Surface
cameraDevice.createCaptureSession(
Collections.singletonList(glSurface), // 关键修改
sessionCallback,
backgroundHandler
);
// 2.配置拍照Surface
//优化尺寸选择(兼容性处理) 配置jpegSizes
Size[] jpegSizes = map.getOutputSizes(ImageFormat.JPEG);
Size captureSize = chooseOptimalSize(jpegSizes);
Log.i(TAG, "使用拍照尺寸: " + captureSize.getWidth() + "x" + captureSize.getHeight());
// 优化:检查尺寸变化,仅当尺寸变更时重建
if (imageReader == null || imageReader.getWidth() != captureSize.getWidth()) {
if (imageReader != null) imageReader.close();
imageReader = ImageReader.newInstance(
captureSize.getWidth(),
captureSize.getHeight(),
ImageFormat.JPEG,
2 // 缓冲区数量
);
}
// 3.配置双输出Surface(预览 + 拍照)
List<Surface> outputSurfaces = new ArrayList<>(2);
outputSurfaces.add(previewSurface);
outputSurfaces.add(imageReader.getSurface());
//3.创建会话
cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
Log.i(TAG, "2.2 预览会话配置成功");
cameraCaptureSession = session;
try {
//3.下发请求添加预览流
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequestBuilder.addTarget(previewSurface);
//配置预览 自动对焦
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
Log.i(TAG, "3.开始下发预览请求");
cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, backgroundHandler);
} catch (CameraAccessException e) {
Log.e(TAG, "设置预览请求失败: " + e.getMessage());
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
Log.e(TAG, "预览会话配置失败");
Toast.makeText(MainActivity.this, "配置失败", Toast.LENGTH_SHORT).show();
}
}, backgroundHandler);
} catch (CameraAccessException e) {
Log.e(TAG, "创建预览会话异常: " + e.getMessage());
}
}
// 优化尺寸选择
private Size chooseOptimalSize(Size[] choices) {
// 优先选择16:9的比例
final double ASPECT_RATIO = 16.0 / 9.0;
Size optimalSize = null;
for (Size size : choices) {
double ratio = (double) size.getWidth() / size.getHeight();
if (Math.abs(ratio - ASPECT_RATIO) <= 0.1) {
if (optimalSize == null ||
size.getWidth() > optimalSize.getWidth()) {
optimalSize = size;
}
}
}
// 若无匹配则选择最大尺寸
if (optimalSize == null) {
for (Size size : choices) {
if (optimalSize == null ||
size.getWidth() > optimalSize.getWidth()) {
optimalSize = size;
}
}
}
return optimalSize != null ? optimalSize : new Size(1920, 1080);
}
private void saveImage(byte[] bytes, File file) {
Log.d(TAG, "保存图像: " + file.getAbsolutePath());
imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
if (imageUri != null) {
try (FileOutputStream output = new FileOutputStream(file)) {
output.write(bytes);
Log.i(TAG, "图像保存成功, 大小: " + bytes.length + " bytes");
} catch (IOException e) {
Log.e(TAG, "保存文件失败: " + e.getMessage());
}
}
}
//触发时机:用户点击授权后调用
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
Log.d(TAG, "权限请求结果: " + requestCode);
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
Log.w(TAG, "用户拒绝相机权限");
Toast.makeText(this, "需要相机权限", Toast.LENGTH_SHORT).show();
finish();
} else {
Log.i(TAG, "用户授予相机权限");
}
}
}
private void startBackgroundThread() {
if (backgroundThread == null) {
backgroundThread = new HandlerThread("CameraBackground");
backgroundThread.start();
backgroundHandler = new Handler(backgroundThread.getLooper());
Log.d(TAG, "后台线程启动");
}
}
private void stopBackgroundThread() {
if (backgroundThread != null) {
Log.d(TAG, "停止后台线程");
backgroundThread.quitSafely();
try {
backgroundThread.join();
backgroundThread = null;
backgroundHandler = null;
} catch (InterruptedException e) {
Log.e(TAG, "停止线程失败: " + e.getMessage());
}
}
}
private void closeCamera() {
Log.d(TAG, "关闭相机资源");
if (isCapturing) {
Log.w(TAG, "正在拍照中,等待完成或取消...");
// 可以尝试等待一段时间或取消请求
try {
cameraCaptureSession.abortCaptures(); // 取消所有进行中的捕获
} catch (CameraAccessException e) {
throw new RuntimeException(e);
}
}
if (cameraCaptureSession != null) {
cameraCaptureSession.close();
cameraCaptureSession = null;
}
isSessionClosed = true;
}
private boolean checkTakePicture() {
if (cameraDevice == null) {
Log.w(TAG, "拍照失败: 相机未初始化");
return false;
}
// 1. 检查会话有效性
if (cameraCaptureSession == null) {
Log.e(TAG, "拍照错误: CameraCaptureSession为空");
return false;
}
// 2. 检查后台Handler
if (backgroundHandler == null) {
Log.e(TAG, "拍照错误: backgroundHandler未初始化");
startBackgroundThread(); // 初始化方法见下方
return false;
}
if (isSessionClosed) {
Log.e(TAG, "当前会话已关闭");
}
return true;
}
private void takePicture() {
Log.i(TAG, "4.开始拍照流程——————————");
try {
//1.检查是否可以拍照
boolean checkFlag = checkTakePicture();
if (!checkFlag) {
Log.i(TAG, "拍照流程————检查未通过!退出拍照!");
return;
}
// 2. 创建拍照请求
CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(imageReader.getSurface());
//3.设置拍照下发参数
//自动曝光
captureBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
// 图片旋转角度跟随手机默认
int rotation = getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, rotation);
// 4. 图像可用监听器
imageReader.setOnImageAvailableListener(reader -> {
Log.d(TAG, "图像数据可用");
try (Image image = reader.acquireLatestImage()) {
if (image != null) {
// 9. 创建目标文件
file = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"pic_" + System.currentTimeMillis() + ".jpg"
);
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
saveImage(bytes, file);
// 发送媒体扫描广播,写入系统相册
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mediaScanIntent.setData(Uri.fromFile(file));
sendBroadcast(mediaScanIntent);
}
} catch (Exception e) {
Log.e(TAG, "保存图像错误: " + e.getMessage());
}
}, backgroundHandler);
// 11. 拍照回调
CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
// 处理拍照完成
isCapturing = false;
// 可以在这里进行后续操作,但注意检查资源是否仍然有效
super.onCaptureCompleted(session, request, result);
Log.i(TAG, "拍照完成,保存至: " + file.getAbsolutePath());
runOnUiThread(() ->
Toast.makeText(MainActivity.this, "保存至: " + file, Toast.LENGTH_SHORT).show()
);
createCameraPreviewSession(); // 恢复预览
}
@Override
public void onCaptureFailed(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull CaptureFailure failure) {
super.onCaptureFailed(session, request, failure);
Log.e(TAG, "拍照失败: " + failure.getReason());
}
};
// 12. 执行拍照(添加会话状态检查)
Log.d(TAG, "停止预览");
cameraCaptureSession.stopRepeating();
Log.d(TAG, "播放黑闪动画");
flash_mode();
Log.d(TAG, "4.下发拍照");
isCapturing = true;
cameraCaptureSession.capture(captureBuilder.build(), captureCallback, backgroundHandler);
} catch (CameraAccessException | IllegalStateException | SecurityException e) {
Log.e(TAG, "拍照过程异常: " + e.getClass().getSimpleName(), e);
}
}
//播放黑闪动画
private void flash_mode() {
// 在拍照按钮点击事件中触发
View flashView = findViewById(R.id.flashview);
flashView.setVisibility(View.VISIBLE); // 先显示黑色视图
// 创建动画:透明度从0到1再到0,模拟闪烁
AlphaAnimation flashAnim = new AlphaAnimation(0.0f, 1.0f);
flashAnim.setDuration(100); // 动画时长100ms,根据需求调整
flashAnim.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
flashView.setVisibility(View.INVISIBLE); // 动画结束后隐藏视图
// 在此处调用实际拍照逻辑(如Camera API)
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
flashView.startAnimation(flashAnim);
}
}
class CameraRenderer2 implements GLSurfaceView.Renderer {
private SurfaceTexture cameraSurfaceTexture;
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// 创建 OES 纹理
int[] texIds = new int[1];
GLES30.glGenTextures(1, texIds, 0);
cameraSurfaceTexture = new SurfaceTexture(texIds[0]);
// 初始化相机
initCameraWithSurface(new Surface(cameraSurfaceTexture));
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
}
@Override
public void onDrawFrame(GL10 gl) {
cameraSurfaceTexture.updateTexImage(); // 更新纹理
// 执行自定义渲染管线...
}
private void initCameraWithSurface(Surface surface) {
// 使用传入的 Surface 创建相机会话
cameraDevice.createCaptureSession(
Collections.singletonList(surface),
sessionCallback,
backgroundHandler
);
}
}
我没听懂你让写的,你直接帮我修改
最新发布