Camera2 媒体记录器 |音频和视频正在异步录制
Camera2 MediaRecorder | Audio and Video are recording asynchronously
我正在构建一个录制视频的应用程序 - 非常简单。我正在使用 Camera2
API 和 MediaRecorder
来实现这一点。我已经可以成功录制视频了,但是声音和视频是异步录制的。
假设我录制了一个 5 秒的视频 - 输出将是一个 10 秒长的视频文件。前 5 秒是播放音频的静止帧,后 5 秒将是没有任何声音的视频帧。就好像 MediaRecorder
在开始接收视频帧之前就开始录制音频了。
我用于测试的设备是三星 Galaxy 7。我设法在网上找到一个人面临类似的问题,但没有 answers/response:Android Audio and Video track playing subsequently
我如何设置 MediaRecorder
:
private void setUpMediaRecorder() throws IOException {
final Activity activity = this;
if (null == activity) {
print("Null activity!");
return;
}
mediaRecorder = new MediaRecorder();
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
if (nextVideoAbsolutePath == null || nextVideoAbsolutePath.isEmpty()) {
nextVideoAbsolutePath = getVideoFilePath(this);
}
mediaRecorder.setOutputFile(nextVideoAbsolutePath);
mediaRecorder.setVideoEncodingBitRate(10000000);
mediaRecorder.setVideoFrameRate(30);
mediaRecorder.setVideoSize(videoSize.getWidth(), videoSize.getHeight());
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
switch (sensorOrientation) {
case SENSOR_ORIENTATION_DEFAULT_DEGREES:
mediaRecorder.setOrientationHint(DEFAULT_ORIENTATIONS.get(rotation));
break;
case SENSOR_ORIENTATION_INVERSE_DEGREES:
mediaRecorder.setOrientationHint(INVERSE_ORIENTATIONS.get(rotation));
break;
}
mediaRecorder.prepare();
}
我的StartRecording()
函数:
void startRecording()
{
//Check the camera and TextureView are ready
if (null == cameraDevice || !textureView.isAvailable() || null == previewSize) {
return;
}
try {
//Close the existing capture session used for preview
closePreviewSession();
//Set up the MediaRecorder
setUpMediaRecorder();
//Compile list of surfaces
List<Surface> surfaces = new ArrayList<>();
surfaces.add(previewSurface);
final Surface recorderSurface = mediaRecorder.getSurface();
surfaces.add(recorderSurface);
// Start the capture session
// Once the session starts, we can update the UI and start recording
cameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
//Store a reference to the session
currentCaptureSession = cameraCaptureSession;
//Flag that recording has started
isRecording = true;
toggleRecordingButton();
try {
//Initiate requestBuilder
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
//Add the surfaces to the request
captureRequestBuilder.addTarget(previewSurface);
captureRequestBuilder.addTarget(recorderSurface);
//Build
captureRequest = captureRequestBuilder.build();
print("CameraCaptureSession stateCallback onConfigured() - Starting media recorder");
//Start recording
mediaRecorder.start();
//Set repeating request for VIDEO
currentCaptureSession.setRepeatingRequest(captureRequest, new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
}
}, null);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
print("onConfigureFailed");
Activity activity = MainActivity.this;
if (null != activity) {
Toast.makeText(activity, "Failed", Toast.LENGTH_SHORT).show();
}
isRecording = false;
}
}, backgroundHandler);
} catch (Exception e) {
e.printStackTrace();
}
}
我的StopRecording()
函数:
private void stopRecording() {
// UI
isRecording = false;
toggleButtonsWhileRecording();
// Stop recording
mediaRecorder.stop();
mediaRecorder.reset();
//Reset path
nextVideoAbsolutePath = null;
}
原来这是一个仅限于某些 Samsung Galaxy 设备的错误。查看有关此问题的更多信息以及检测长帧并在录制后更正它的解决方法:
Saved video file only has one video frame
总而言之,该错误与这些设备从深度睡眠中恢复有关。重置 phone 后,问题就解决了(但如果我让 phone 进入深度睡眠,问题又回来了)。
我正在构建一个录制视频的应用程序 - 非常简单。我正在使用 Camera2
API 和 MediaRecorder
来实现这一点。我已经可以成功录制视频了,但是声音和视频是异步录制的。
假设我录制了一个 5 秒的视频 - 输出将是一个 10 秒长的视频文件。前 5 秒是播放音频的静止帧,后 5 秒将是没有任何声音的视频帧。就好像 MediaRecorder
在开始接收视频帧之前就开始录制音频了。
我用于测试的设备是三星 Galaxy 7。我设法在网上找到一个人面临类似的问题,但没有 answers/response:Android Audio and Video track playing subsequently
我如何设置 MediaRecorder
:
private void setUpMediaRecorder() throws IOException {
final Activity activity = this;
if (null == activity) {
print("Null activity!");
return;
}
mediaRecorder = new MediaRecorder();
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
if (nextVideoAbsolutePath == null || nextVideoAbsolutePath.isEmpty()) {
nextVideoAbsolutePath = getVideoFilePath(this);
}
mediaRecorder.setOutputFile(nextVideoAbsolutePath);
mediaRecorder.setVideoEncodingBitRate(10000000);
mediaRecorder.setVideoFrameRate(30);
mediaRecorder.setVideoSize(videoSize.getWidth(), videoSize.getHeight());
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
switch (sensorOrientation) {
case SENSOR_ORIENTATION_DEFAULT_DEGREES:
mediaRecorder.setOrientationHint(DEFAULT_ORIENTATIONS.get(rotation));
break;
case SENSOR_ORIENTATION_INVERSE_DEGREES:
mediaRecorder.setOrientationHint(INVERSE_ORIENTATIONS.get(rotation));
break;
}
mediaRecorder.prepare();
}
我的StartRecording()
函数:
void startRecording()
{
//Check the camera and TextureView are ready
if (null == cameraDevice || !textureView.isAvailable() || null == previewSize) {
return;
}
try {
//Close the existing capture session used for preview
closePreviewSession();
//Set up the MediaRecorder
setUpMediaRecorder();
//Compile list of surfaces
List<Surface> surfaces = new ArrayList<>();
surfaces.add(previewSurface);
final Surface recorderSurface = mediaRecorder.getSurface();
surfaces.add(recorderSurface);
// Start the capture session
// Once the session starts, we can update the UI and start recording
cameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
//Store a reference to the session
currentCaptureSession = cameraCaptureSession;
//Flag that recording has started
isRecording = true;
toggleRecordingButton();
try {
//Initiate requestBuilder
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
//Add the surfaces to the request
captureRequestBuilder.addTarget(previewSurface);
captureRequestBuilder.addTarget(recorderSurface);
//Build
captureRequest = captureRequestBuilder.build();
print("CameraCaptureSession stateCallback onConfigured() - Starting media recorder");
//Start recording
mediaRecorder.start();
//Set repeating request for VIDEO
currentCaptureSession.setRepeatingRequest(captureRequest, new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
}
}, null);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
print("onConfigureFailed");
Activity activity = MainActivity.this;
if (null != activity) {
Toast.makeText(activity, "Failed", Toast.LENGTH_SHORT).show();
}
isRecording = false;
}
}, backgroundHandler);
} catch (Exception e) {
e.printStackTrace();
}
}
我的StopRecording()
函数:
private void stopRecording() {
// UI
isRecording = false;
toggleButtonsWhileRecording();
// Stop recording
mediaRecorder.stop();
mediaRecorder.reset();
//Reset path
nextVideoAbsolutePath = null;
}
原来这是一个仅限于某些 Samsung Galaxy 设备的错误。查看有关此问题的更多信息以及检测长帧并在录制后更正它的解决方法: Saved video file only has one video frame
总而言之,该错误与这些设备从深度睡眠中恢复有关。重置 phone 后,问题就解决了(但如果我让 phone 进入深度睡眠,问题又回来了)。