private void startPreview() { try { createPreviewSession(); }catch (CameraAccessException e) { e.printStackTrace(); } } Exception 'android.hardware.camera2.CameraAccessException' is never thrown in the corresponding try block
时间: 2023-12-25 16:06:47 浏览: 24
这段代码中的异常抛出是针对 `createPreviewSession()` 方法可能会抛出的 `CameraAccessException` 异常进行处理。但是根据代码看来,`createPreviewSession()` 方法并没有抛出该异常,因此该异常处理代码实际上是无用的。
这可能是因为代码作者在编写时,可能考虑到该方法可能会抛出该异常,但是后来修改了该方法的实现,使得其不再抛出该异常,但是忘记了删除相应的异常处理代码。
可以将该异常处理代码删除,或者根据代码实际情况修改为正确的异常处理方式。
相关问题
上面的代码没有cameraHelper.setPreviewCallback
非常抱歉,我的回答有误。你是对的,确实需要使用`cameraHelper.setPreviewCallback`方法来设置相机预览回调。以下是修改后的代码:
```
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.ImageView;
import androidx.appcompat.app.AppCompatActivity;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.github.chrisbanes.photoview.PhotoView;
import com.herohan.uvcapp.CameraHelper;
import com.herohan.uvcapp.ICameraHelper;
import java.io.IOException;
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {
private static final String TAG = "MainActivity";
private ICameraHelper cameraHelper;
private SurfaceView surfaceView;
private SurfaceHolder surfaceHolder;
private PhotoView photoView;
private byte[] lastFrameData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化相机助手
cameraHelper = new CameraHelper(this);
// 获取SurfaceView和PhotoView对象
surfaceView = findViewById(R.id.surface_view);
photoView = findViewById(R.id.photo_view);
// 设置PhotoView的缩放类型
photoView.setScaleType(ImageView.ScaleType.FIT_CENTER);
// 设置PhotoView的缩放最小值和最大值
photoView.setMinimumScale(0.5f);
photoView.setMaximumScale(10f);
// 获取SurfaceHolder对象并添加回调
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
}
@Override
protected void onResume() {
super.onResume();
// 打开相机
cameraHelper.openCamera();
}
@Override
protected void onPause() {
super.onPause();
// 关闭相机
cameraHelper.closeCamera();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// 设置相机预览的SurfaceHolder
cameraHelper.setPreviewDisplay(holder);
// 开始预览
cameraHelper.startPreview();
// 设置相机预览回调
cameraHelper.setPreviewCallback(new ICameraHelper.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, int width, int height) {
Log.d(TAG, "onPreviewFrame: " + data.length);
// 如果上一帧数据还没有处理完,则直接返回
if (lastFrameData != null) {
return;
}
// 将当前帧数据保存到lastFrameData中
lastFrameData = data.clone();
// 使用Glide库加载Bitmap对象到PhotoView中
RequestOptions options = new RequestOptions()
.placeholder(R.drawable.placeholder)
.error(R.drawable.error);
Glide.with(MainActivity.this)
.load(getBitmapFromFrame(data, width, height))
.apply(options)
.into(photoView);
}
});
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// 停止预览
cameraHelper.stopPreview();
}
// 按钮点击事件,切换相机前后摄像头
public void switchCamera(View view) {
cameraHelper.switchCamera();
}
// 将相机预览数据转换为Bitmap对象
private Bitmap getBitmapFromFrame(byte[] data, int width, int height) {
Bitmap bitmap = null;
try {
YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21, width, height, null);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(0, 0, width, height), 100, outputStream);
byte[] jpegData = outputStream.toByteArray();
bitmap = BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length);
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
}
```
在`MainActivity`中实现了`SurfaceHolder.Callback`接口,将`SurfaceView`的`SurfaceHolder`对象传递给相机助手对象,然后在`surfaceCreated`回调方法中,设置相机预览回调,将相机预览数据转换为`Bitmap`对象并加载到`PhotoView`中。
同时将相机预览回调中的数据保存到`lastFrameData`中,如果上一帧数据还没有处理完,则直接返回,保证每次只处理一帧数据。
android视频录制动态添加时间水印
如果要在 Android 视频录制过程中动态添加时间水印,可以使用 Camera2 API 实现。Camera2 API 可以获取到每一帧视频的数据,因此可以在每一帧数据上添加时间水印,并将处理后的数据传递给 MediaRecorder 进行录制。
以下是添加动态时间水印的示例代码:
```
private CameraDevice mCameraDevice;
private CaptureRequest.Builder mPreviewBuilder;
private ImageReader mImageReader;
private Surface mRecorderSurface;
private void initCamera() {
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
String cameraId = CameraCharacteristics.LENS_FACING_BACK + "";
try {
manager.openCamera(cameraId, new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice cameraDevice) {
mCameraDevice = cameraDevice;
startPreview();
}
@Override
public void onDisconnected(@NonNull CameraDevice cameraDevice) {
mCameraDevice.close();
mCameraDevice = null;
}
@Override
public void onError(@NonNull CameraDevice cameraDevice, int i) {
mCameraDevice.close();
mCameraDevice = null;
}
}, null);
} catch (Exception e) {
e.printStackTrace();
}
}
private void startPreview() {
try {
SurfaceTexture surfaceTexture = new SurfaceTexture(0);
surfaceTexture.setDefaultBufferSize(640, 480);
Surface previewSurface = new Surface(surfaceTexture);
mImageReader = ImageReader.newInstance(640, 480, ImageFormat.YUV_420_888, 2);
mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] data = new byte[buffer.remaining()];
buffer.get(data);
addTimeWatermark(data, image.getWidth(), image.getHeight());
image.close();
}
}, null);
mRecorderSurface = mMediaRecorder.getSurface();
mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewBuilder.addTarget(previewSurface);
mPreviewBuilder.addTarget(mImageReader.getSurface());
mCameraDevice.createCaptureSession(Arrays.asList(previewSurface, mImageReader.getSurface(), mRecorderSurface), new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
try {
cameraCaptureSession.setRepeatingRequest(mPreviewBuilder.build(), null, null);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
}
}, null);
} catch (Exception e) {
e.printStackTrace();
}
}
private void addTimeWatermark(byte[] data, int width, int height) {
YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21, width, height, null);
ByteArrayOutputStream out = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(0, 0, width, height), 100, out);
byte[] jpegData = out.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length);
Canvas canvas = new Canvas(bitmap);
canvas.drawText(getCurrentTime(), 10, 10, new Paint());
canvas.save();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
byte[] outputData = outputStream.toByteArray();
try {
mRecorderSurface.lockCanvas(null).drawBitmap(bitmap, 0, 0, null);
mMediaRecorder.writeSampleData(mRecorderSurface, ByteBuffer.wrap(outputData), new MediaCodec.BufferInfo());
} catch (Exception e) {
e.printStackTrace();
} finally {
mRecorderSurface.unlockCanvasAndPost(canvas);
}
}
```
需要注意的是,在添加时间水印时,要将视频帧转换为 Bitmap 对象,并在 Bitmap 上绘制时间水印。然后,将处理后的数据传递给 MediaRecorder 进行录制。同时,要在 CameraDevice.close() 方法被调用时,释放资源。