I have implemented Camera2 API of Android using MediaRecorder
to record video from the Camera. The Camera Previews are working fine and the video file is also created successfully without any errors. However, the output video is blank and has white flickering lines.
This is the output video I get.
The code for preparing MediaRecorder
val surface = MediaCodec.createPersistentInputSurface()
surface.release()
val outputFile = createFile(applicationContext,"mp4")
val mMediaRecorder = MediaRecorder()
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC)
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE)
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
mMediaRecorder.setOutputFile(outputFile.absolutePath)
mMediaRecorder.setVideoEncodingBitRate(10_000_000)
mMediaRecorder.setVideoFrameRate(30)
mMediaRecorder.setVideoSize(matchedResolution.width, matchedResolution.height)
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264)
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
mMediaRecorder.setInputSurface(surface)
Creating the session.
val previewSurface = surfaceView2.holder.surface
val captureCallbackVideo =
object : CameraCaptureSession.StateCallback() {
override fun onConfigureFailed(session: CameraCaptureSession) {}
override fun onConfigured(session: CameraCaptureSession) {
// session configured
val previewRequestBuilder =
cameraDevice.createCaptureRequest(TEMPLATE_RECORD)
.apply {
addTarget(previewSurface)
addTarget(surface)
set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, Range(30,30))
}
session.setRepeatingRequest(
previewRequestBuilder.build(),
null,
Handler { true }
)
}
}
cameraDevice.createCaptureSession(mutableListOf(previewSurface, surface), captureCallbackVideo, Handler { true })
For starting the recording
mMediaRecorder.prepare()
mMediaRecorder.start()
For stopping
mMediaRecorder.stop()
mMediaRecorder.release()
I had figured it out. The problem was with the input surface of MediaRecorder
. Apparently, the way of Google's code of camera2
at GitHub is not right in setting up the Surface
for MediaRecorder
correctly.
The solution is that we should not provide Surface
as input to the MediaRecorder, but prepare
the MediaRecorder
without a Surface
and then use its internal Surface
for our CaptureRequest
mMediaRecorder = MediaRecorder()
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE)
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
mMediaRecorder.setVideoEncodingBitRate(10_000_000)
//Uncomment on physical device, comment on emulator
//mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264)
mMediaRecorder.setVideoSize(matchedResolution.width, matchedResolution.height)
mMediaRecorder.setVideoFrameRate(30)
mMediaRecorder.setOutputFile(outputFile.absolutePath)
try {
mMediaRecorder.prepare()
} catch (e: java.lang.Exception) {
e.printStackTrace()
return
}
For creating session
val previewSurface = surfaceView2.holder.surface
val captureCallbackVideo =
object : CameraCaptureSession.StateCallback() {
override fun onConfigureFailed(session: CameraCaptureSession) {}
override fun onConfigured(session: CameraCaptureSession) {
// session configured
val previewRequestBuilder =
cameraDevice.createCaptureRequest(TEMPLATE_RECORD)
.apply {
addTarget(previewSurface)
addTarget(mMediaRecorder.surface)
set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, Range(30,30))
}
session.setRepeatingRequest(
previewRequestBuilder.build(),
null,
Handler { true }
)
}
}
cameraDevice.createCaptureSession(mutableListOf(previewSurface, mMediaRecorder.surface), captureCallbackVideo, Handler { true })
For starting recording:
mMediaRecorder.start()
For stopping a recording:
mMediaRecorder.stop()
mMediaRecorder.release()