Reputation: 774
I am building an app that records video - quite simple. I am using the Camera2
API along with MediaRecorder
to achieve this. I have been able to successfully record video, but the sound and video are recording asynchronously.
Let's say I record a 5 second video - the output will be a video file that is 10 seconds in length. The first 5 seconds is a still frame playing the audio, the last 5 seconds will be the video frames without any sound. It is as if the MediaRecorder
is recording the audio before it even begins to receive video frames.
Device I am using for testing is a Samsung Galaxy 7. I managed to find one person online facing a similar issue with no answers/response: Android Audio and Video track playing subsequently
How I set up my 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();
}
My StartRecording()
function:
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();
}
}
My StopRecording()
function:
private void stopRecording() {
// UI
isRecording = false;
toggleButtonsWhileRecording();
// Stop recording
mediaRecorder.stop();
mediaRecorder.reset();
//Reset path
nextVideoAbsolutePath = null;
}
Upvotes: 1
Views: 1616
Reputation: 774
Turns out this is a bug limited to certain Samsung Galaxy devices only. See more about this issue and a workaround for detecting the long frame and correcting it after recording: Saved video file only has one video frame
In summary, the bug is related to these devices coming out of Deep Sleep. After resetting the phone, problem is solved (but comes back if I let the phone go into Deep Sleep).
Upvotes: 2