I have been struggling for some time now on why I am not able to record for a second time with MediaRecorder. Every time I try it says:
Caused by: java.io.IOException: prepare failed.
I am not sure what I am doing wrong and frankly I have been staring at this for too long. I am doing this in Kotlin, but for the most part it is the same as Java with the exception of the function syntax. Please can anyone help? I have looked at others and the camera2 and mediarecorder being implemented, but it isn't working.
private val cameraCaptureCallback = object : CameraCaptureSession.CaptureCallback() {
private fun process(result: CaptureResult){
when(cameraState) {
STATE_PREVIEW -> {}
STATE_WAITING_LOCK -> {
val afState = result.get(CaptureResult.CONTROL_AF_STATE)
if(afState == null){
captureImage()
} else if(CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState
|| CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState){
val aeState = result.get(CaptureResult.CONTROL_AE_STATE)
if(aeState == null
|| aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED){
cameraState = STATE_PICTURE_TAKEN
captureImage()
} else {
runPrecaptureSequence()
}
}
}
STATE_WAITING_PRECAPTURE -> {
val aeState = result.get(CaptureResult.CONTROL_AE_STATE)
if(aeState == null
|| aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE
|| aeState == CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED) {
cameraState = STATE_WAITING_NON_PRECAPTURE
}
}
STATE_WAITING_NON_PRECAPTURE -> {
val aeState = result.get(CaptureResult.CONTROL_AE_STATE)
if(aeState == null
|| aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
cameraState = STATE_PICTURE_TAKEN
captureImage()
}
}
}
}
override fun onCaptureProgressed(session: CameraCaptureSession?, request: CaptureRequest?, partialResult: CaptureResult?) {
process(partialResult!!)
}
override fun onCaptureCompleted(session: CameraCaptureSession?, request: CaptureRequest?, result: TotalCaptureResult?) {
process(result!!)
}
}
private val cameraStateCallback = object : CameraDevice.StateCallback() {
override fun onOpened(camera: CameraDevice) {
cameraDevice = camera
createCameraPreview()
}
override fun onDisconnected(camera: CameraDevice) {
camera.close()
cameraDevice = null
}
override fun onError(camera: CameraDevice, error: Int) {
camera.close()
cameraDevice = null
if(activity != null)
activity.finish()
}
}
private val textureListener: TextureView.SurfaceTextureListener = object : TextureView.SurfaceTextureListener {
override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
//open your camera here
setupCamera(width, height)
}
override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {
}
override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
return true
}
override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {}
}
private val previewTextureListener: TextureView.SurfaceTextureListener = object : TextureView.SurfaceTextureListener {
override fun onSurfaceTextureAvailable(surface: SurfaceTexture?, width: Int, height: Int) {
try {
if(contentCaptured == "video"){
previewNewPostVideoMediaPlayer = MediaPlayer()
previewNewPostVideoMediaPlayer?.setDataSource(videoFile?.absolutePath)
previewNewPostVideoMediaPlayer?.setSurface(Surface(surface))
previewNewPostVideoMediaPlayer?.prepare()
previewNewPostVideoMediaPlayer?.start()
}
} catch (e: IllegalArgumentException ) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (e: SecurityException ) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (e: IllegalStateException ) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (e: IOException) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
override fun onSurfaceTextureSizeChanged(p0: SurfaceTexture?, p1: Int, p2: Int) {
}
override fun onSurfaceTextureUpdated(surfaceTexture: SurfaceTexture?) {
}
override fun onSurfaceTextureDestroyed(p0: SurfaceTexture?): Boolean {
return true
}
}
private fun createCameraPreview() {
if (cameraDevice == null || !cameraTextureView?.isAvailable!! || cameraPreviewDimension == null) {
return
}
try {
var texture: SurfaceTexture = cameraTextureView!!.surfaceTexture
texture.setDefaultBufferSize(cameraPreviewDimension!!.width, cameraPreviewDimension!!.height)
var surfaces: MutableList<Surface> = ArrayList()
captureRequestBuilder = cameraDevice?.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
captureRequestBuilder?.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO)
var surface = Surface(texture)
captureRequestBuilder?.addTarget(surface)
surfaces.add(surface)
surfaces.add(cameraPreviewImageReader?.surface!!)
cameraDevice?.createCaptureSession(surfaces, object : CameraCaptureSession.StateCallback() {
override fun onConfigured(session: CameraCaptureSession?) {
if (cameraDevice == null) {
return
}
try {
cameraCaptureSession = session
cameraCaptureSession?.setRepeatingRequest(captureRequestBuilder?.build(), null, mBackgroundHandler)
} catch (e: CameraAccessException){
e.printStackTrace()
}
}
override fun onConfigureFailed(cameraCaptureSession: CameraCaptureSession?) {
Log.e("Configuration session", "camera capture session failed in create preview")
}
}, mBackgroundHandler)
} catch(e: CameraAccessException) {
e.printStackTrace()
}
}
private fun createCameraOutput(width: Int, height: Int){
var cameraManager: CameraManager = activity.getSystemService(Context.CAMERA_SERVICE) as CameraManager
try {
var cameraId = cameraManager.cameraIdList[0]
var cameraChars: CameraCharacteristics? = cameraManager.getCameraCharacteristics(cameraId)
var map: StreamConfigurationMap = cameraChars?.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)!!
var max: Size = map.getOutputSizes(ImageFormat.JPEG)[0]
imageFile = createImageFile()
cameraPreviewImageReader = ImageReader.newInstance(max.width, max.height, ImageFormat.JPEG, 2)
cameraPreviewImageReader?.setOnImageAvailableListener(OnImageAvailableListener, mBackgroundHandler)
videoSize = map.getOutputSizes(SurfaceTexture::class.java)[0]
cameraPreviewDimension = map.getOutputSizes(SurfaceTexture::class.java)[0]
videoTextureView?.setAspectRatio(cameraPreviewDimension?.height!!, cameraPreviewDimension?.width!!)
cameraTextureView?.setAspectRatio(cameraPreviewDimension?.height!!, cameraPreviewDimension?.width!!)
configureTransform(width, height)
var available: Boolean = cameraChars.get(CameraCharacteristics.FLASH_INFO_AVAILABLE)
mFlashSupported = available == null ?: available
cameraDeviceId = cameraId
} catch(e: CameraAccessException) {
e.printStackTrace()
}
}
private fun setupCamera(width: Int, height: Int) {
if(ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
var mainActivity = activity as MainActivity
ActivityCompat.requestPermissions(mainActivity!!, arrayOf(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_CAMERA_PERMISSION)
return
}
var cameraManager: CameraManager = activity.getSystemService(Context.CAMERA_SERVICE) as CameraManager
createCameraOutput(width, height)
try {
cameraManager.openCamera(cameraDeviceId, cameraStateCallback, null)
cameraPreviewFrameLayout?.setOnTouchListener(OnCameraFeaturesListener)
} catch (e: CameraAccessException) {
e.printStackTrace()
} catch (e: InterruptedException) {
throw RuntimeException("Interrupted while trying to lock camera opening.", e);
}
}
private fun updateCameraPreview() {
if(cameraDevice == null) {
return
}
try {
cameraCaptureSession?.setRepeatingRequest(captureRequestBuilder?.build(), cameraCaptureCallback, mBackgroundHandler)
} catch(e: CameraAccessException) {
e.printStackTrace()
}
}
private fun takePicture(){
initFocus()
}
private fun initFocus(){
try {
captureRequestBuilder?.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START)
cameraState = STATE_WAITING_LOCK
cameraCaptureSession?.capture(captureRequestBuilder?.build(), cameraCaptureCallback, mBackgroundHandler)
} catch (e: CameraAccessException) {
e.printStackTrace()
}
}
private fun releaseFocus(){
try {
captureRequestBuilder?.set(CaptureRequest.CONTROL_AF_TRIGGER,
CameraMetadata.CONTROL_AF_TRIGGER_CANCEL)
cameraCaptureSession?.capture(captureRequestBuilder?.build(), null, mBackgroundHandler)
cameraState = STATE_PREVIEW
cameraCaptureSession?.setRepeatingRequest(captureRequestBuilder?.build(), cameraCaptureCallback, mBackgroundHandler)
} catch (e: CameraAccessException ) {
e.printStackTrace()
}
}
private fun runPrecaptureSequence() {
try {
captureRequestBuilder?.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START)
cameraState = STATE_WAITING_PRECAPTURE;
cameraCaptureSession?.capture(captureRequestBuilder?.build(), cameraCaptureCallback,
mBackgroundHandler)
} catch (e: CameraAccessException ) {
e.printStackTrace()
}
}
private fun captureImage() {
if(cameraDevice == null){
return
}
try {
var tempCaptureBuilder: CaptureRequest.Builder = cameraDevice?.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE)!!
tempCaptureBuilder.addTarget(cameraPreviewImageReader?.surface!!)
var camManager: CameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
var camChars: CameraCharacteristics = camManager.getCameraCharacteristics(cameraDevice?.id)
var rotation: Int = activity.windowManager.defaultDisplay.rotation
var actualRotation = getJpegOrientation(camChars, rotation)
tempCaptureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(actualRotation))
var tempCallback = object: CameraCaptureSession.CaptureCallback() {
override fun onCaptureCompleted(session: CameraCaptureSession?, request: CaptureRequest?, result: TotalCaptureResult?) {
releaseFocus()
}
}
cameraCaptureSession?.capture(tempCaptureBuilder.build(), tempCallback, null)
}
private fun setupRecorder() {
try {
videoFile = createVideoFile()
videoPath = videoFile?.path
} catch (e: IOException) {
e.printStackTrace()
}
if(mediaRecorder == null) {
mediaRecorder = MediaRecorder()
}
mediaRecorder?.setAudioSource(MediaRecorder.AudioSource.MIC)
mediaRecorder?.setVideoSource(MediaRecorder.VideoSource.SURFACE)
mediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
mediaRecorder?.setVideoEncoder(MediaRecorder.VideoEncoder.H264)
mediaRecorder?.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
mediaRecorder?.setOutputFile(videoPath)
mediaRecorder?.setVideoSize(videoSize?.width!!, videoSize?.height!!)
mediaRecorder?.setVideoFrameRate(30)
mediaRecorder?.setVideoEncodingBitRate(10000000)
mediaRecorder?.setOrientationHint(90)
}
private fun startRecordingVideo() {
if(cameraDevice == null || cameraPreviewDimension == null || !cameraTextureView?.isAvailable!!) {
return
}
try {
closeCameraSession()
setupRecorder()
mediaRecorder?.prepare()
var texture = cameraTextureView?.surfaceTexture
texture?.setDefaultBufferSize(cameraPreviewDimension?.width!!, cameraPreviewDimension?.height!!)
captureRequestBuilder = cameraDevice?.createCaptureRequest(CameraDevice.TEMPLATE_RECORD)
captureRequestBuilder?.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO)
captureRequestBuilder?.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON)
var surfaces: MutableList<Surface> = ArrayList()
var previewSurface = Surface(texture)
var recorderSurface = mediaRecorder?.surface!!
Log.i("media recorder",mediaRecorder?.surface!!.toString())
var imageReaderSurface = cameraPreviewImageReader?.surface!!
surfaces.add(previewSurface)
surfaces.add(recorderSurface)
captureRequestBuilder?.addTarget(recorderSurface)
captureRequestBuilder?.addTarget(previewSurface)
cameraDevice?.createCaptureSession(surfaces, object : CameraCaptureSession.StateCallback() {
override fun onConfigured(session: CameraCaptureSession?) {
recordCaptureSession = session
try {
recordCaptureSession?.setRepeatingRequest(captureRequestBuilder?.build(), null, mBackgroundHandler)
} catch(e: CameraAccessException){
e.printStackTrace()
}
activity.runOnUiThread {
mediaRecorder?.start()
}
}
override fun onConfigureFailed(session: CameraCaptureSession?) {
Log.e("capture session error","session error")
}
}, mBackgroundHandler)
} catch(e: CameraAccessException){
e.printStackTrace()
}
}
private fun stopRecordingVideo() {
recordCaptureSession?.stopRepeating()
recordCaptureSession?.abortCaptures()
createCameraPreview()
if(mediaRecorder != null){
try {
} catch(e: CameraAccessException){
e.printStackTrace()
}
mediaRecorder?.stop()
mediaRecorder?.reset()
mediaRecorder?.setAudioSource(MediaRecorder.AudioSource.MIC)
mediaRecorder?.setVideoSource(MediaRecorder.VideoSource.SURFACE)
mediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
mediaRecorder?.setVideoEncoder(MediaRecorder.VideoEncoder.H264)
mediaRecorder?.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
mediaRecorder?.setOutputFile(videoPath)
mediaRecorder?.setVideoSize(videoSize?.width!!, videoSize?.height!!)
mediaRecorder?.setVideoFrameRate(30)
mediaRecorder?.setVideoEncodingBitRate(10000000)
mediaRecorder?.setOrientationHint(90)
}
}
private fun startBackgroundThread() {
mBackgroundThread = HandlerThread("CameraBackground")
mBackgroundThread?.start()
mBackgroundHandler = Handler(mBackgroundThread?.looper)
}
private fun stopBackgroundThread() {
mBackgroundThread?.quitSafely()
try {
mBackgroundThread?.join()
mBackgroundThread = null
mBackgroundHandler = null
} catch(e: InterruptedException) {
e.printStackTrace()
}
}
private fun closeCamera() {
try {
if (cameraCaptureSession != null) {
cameraCaptureSession?.close()
cameraCaptureSession = null
}
if (cameraDevice != null) {
cameraDevice?.close()
cameraDevice = null
}
if(cameraPreviewImageReader != null){
cameraPreviewImageReader?.close()
cameraPreviewImageReader = null
}
if(mediaRecorder != null){
mediaRecorder?.reset()
mediaRecorder?.release()
mediaRecorder = null
}
} catch (e: InterruptedException) {
throw RuntimeException("Interrupted while trying to lock camera closing.", e)
}
}