使用 Android 的 Camera2 API 进行视频广播
Video broadcast with Android's Camera2 API
我正在尝试制作一个通过互联网播放视频的应用程序,目前我正在使用已弃用的相机 API,向相机对象添加一个 Camera.PreviewCallback,然后发送字节数组来自 Camera.PreviewCallback.
的 onPreviewFrame() 方法
但现在我想测试新的 Camera2 API,我正在 Camera2BasicTutorial 观看,我认为我需要制作一个 CameraCaptureSession.CaptureCallback 对象来获取图像字节数组,就像教程说的那样:
CameraCaptureSession.CaptureCallback CaptureCallback
= new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
showToast("Saved: " + mFile);
Log.d(TAG, mFile.toString());
unlockFocus();
}
};
然后添加到CameraCaptureSession中:
mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
问题是我不知道如何从 CaptureCallback 的 onCaptureCompleted() 中的任何参数中检索每个图像字节数组。
有什么帮助吗?
你说得对 - 你无法从 onCaptureCompleted()
方法中获取图像数据。该回调仅 returns 有关您自己簿记的曝光的元数据。实际图像信息会发送到您在曝光 CaptureRequest
中指定的任何 Surface
。
至少我意识到如何做我想做的事情,从Camera2BasicTutorial开始,我对Camera2BasicFragment做了以下更改class:
修改 captureStillPicture() 方法以删除我认为对我的广播不需要的东西,也不允许此方法停止重复模式:
private void captureStillPicture() {
try {
final Activity activity = getActivity();
if (null == activity || null == mCameraDevice) {
return;
}
final CaptureRequest.Builder captureBuilder =
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(mImageReader.getSurface());
CameraCaptureSession.CaptureCallback CaptureCallback
= new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
}
};
mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
在createCameraPreviewSession()方法中,关闭自动闪光:
// When the session is ready, we start displaying the preview.
mCaptureSession = cameraCaptureSession;
try {
// Auto focus should be continuous for camera preview.
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
// Flash is automatically enabled when necessary.
// mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
// CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
// Finally, we start displaying the camera preview.
mPreviewRequest = mPreviewRequestBuilder.build();
mCaptureSession.setRepeatingRequest(mPreviewRequest,
mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
我创建了一个布尔变量来检测当前是否有图像正在处理,而不是将相机捕获的所有帧排队;和另一个布尔值来跟踪是否有通过互联网发送的帧:
private boolean mWorking = false;
private boolean mNetworkWorking = false;
将CaptureCallback对象修改为运行每帧中的captureStillPicture()方法(仅当当前没有帧处理时)
case STATE_PREVIEW: {
if (!mWorking){
Log.d(TAG, "capturing..");
mWorking = true;
mBackgroundHandler.post(new Runnable() {
@Override
public void run() {
captureStillPicture();
}
});
} else {
Log.d(TAG, "thread working, doing nothing");
}
break;
最后,读取帧并发送;我实现了这个修改 OnImageAvailableListener 对象:
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
= new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(final ImageReader reader) {
// Process the image.
Image image = reader.acquireNextImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
final byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
image.close();
if (!mNetworkWorking){
Thread thread = new Thread(){
@Override
public void run(){
mNetworkWorking = true;
HttpResponse response = null;
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(mBroadcastUrl);
post.setEntity(new ByteArrayEntity(bytes));
try {
response = client.execute(post);
} catch (ClientProtocolException e) {
if (BuildConfig.LOCAL_LOG)
Log.w(TAG, "ClientProtocolException: "+e.getMessage());
} catch (IOException e) {
if (BuildConfig.LOCAL_LOG)
Log.w(TAG, "IOException: "+e.getMessage());
}
mNetworkWorking = false;
}
};
thread.setName("networkThread");
thread.setPriority(Thread.MAX_PRIORITY);
thread.start();
}
mWorking = false;
}
};
就这些了。
我正在尝试制作一个通过互联网播放视频的应用程序,目前我正在使用已弃用的相机 API,向相机对象添加一个 Camera.PreviewCallback,然后发送字节数组来自 Camera.PreviewCallback.
的 onPreviewFrame() 方法但现在我想测试新的 Camera2 API,我正在 Camera2BasicTutorial 观看,我认为我需要制作一个 CameraCaptureSession.CaptureCallback 对象来获取图像字节数组,就像教程说的那样:
CameraCaptureSession.CaptureCallback CaptureCallback
= new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
showToast("Saved: " + mFile);
Log.d(TAG, mFile.toString());
unlockFocus();
}
};
然后添加到CameraCaptureSession中:
mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
问题是我不知道如何从 CaptureCallback 的 onCaptureCompleted() 中的任何参数中检索每个图像字节数组。
有什么帮助吗?
你说得对 - 你无法从 onCaptureCompleted()
方法中获取图像数据。该回调仅 returns 有关您自己簿记的曝光的元数据。实际图像信息会发送到您在曝光 CaptureRequest
中指定的任何 Surface
。
至少我意识到如何做我想做的事情,从Camera2BasicTutorial开始,我对Camera2BasicFragment做了以下更改class:
修改 captureStillPicture() 方法以删除我认为对我的广播不需要的东西,也不允许此方法停止重复模式:
private void captureStillPicture() { try { final Activity activity = getActivity(); if (null == activity || null == mCameraDevice) { return; } final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); captureBuilder.addTarget(mImageReader.getSurface()); CameraCaptureSession.CaptureCallback CaptureCallback = new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { } }; mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null); } catch (CameraAccessException e) { e.printStackTrace(); } }
在createCameraPreviewSession()方法中,关闭自动闪光:
// When the session is ready, we start displaying the preview. mCaptureSession = cameraCaptureSession; try { // Auto focus should be continuous for camera preview. mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // Flash is automatically enabled when necessary. // mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, // CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); // Finally, we start displaying the camera preview. mPreviewRequest = mPreviewRequestBuilder.build(); mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); }
我创建了一个布尔变量来检测当前是否有图像正在处理,而不是将相机捕获的所有帧排队;和另一个布尔值来跟踪是否有通过互联网发送的帧:
private boolean mWorking = false; private boolean mNetworkWorking = false;
将CaptureCallback对象修改为运行每帧中的captureStillPicture()方法(仅当当前没有帧处理时)
case STATE_PREVIEW: { if (!mWorking){ Log.d(TAG, "capturing.."); mWorking = true; mBackgroundHandler.post(new Runnable() { @Override public void run() { captureStillPicture(); } }); } else { Log.d(TAG, "thread working, doing nothing"); } break;
最后,读取帧并发送;我实现了这个修改 OnImageAvailableListener 对象:
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(final ImageReader reader) { // Process the image. Image image = reader.acquireNextImage(); ByteBuffer buffer = image.getPlanes()[0].getBuffer(); final byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes); image.close(); if (!mNetworkWorking){ Thread thread = new Thread(){ @Override public void run(){ mNetworkWorking = true; HttpResponse response = null; HttpClient client = new DefaultHttpClient(); HttpPost post = new HttpPost(mBroadcastUrl); post.setEntity(new ByteArrayEntity(bytes)); try { response = client.execute(post); } catch (ClientProtocolException e) { if (BuildConfig.LOCAL_LOG) Log.w(TAG, "ClientProtocolException: "+e.getMessage()); } catch (IOException e) { if (BuildConfig.LOCAL_LOG) Log.w(TAG, "IOException: "+e.getMessage()); } mNetworkWorking = false; } }; thread.setName("networkThread"); thread.setPriority(Thread.MAX_PRIORITY); thread.start(); } mWorking = false; } };
就这些了。