add some video recording handling

This commit is contained in:
tibbi 2018-06-06 21:50:09 +02:00
parent 9e3e732bbf
commit 6c885c83c2
4 changed files with 133 additions and 17 deletions

View File

@ -265,15 +265,7 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener {
toggleBottomButtons(true)
mPreview?.tryTakePicture()
} else {
if (mPreview?.toggleRecording() == true) {
shutter.setImageResource(R.drawable.ic_video_stop)
toggle_camera.beInvisible()
showTimer()
} else {
shutter.setImageResource(R.drawable.ic_video_rec)
showToggleCameraIfNeeded()
hideTimer()
}
mPreview?.toggleRecording()
}
}
@ -526,6 +518,20 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener {
mIsCameraAvailable = available
}
fun setRecordingState(isRecording: Boolean) {
runOnUiThread {
if (isRecording) {
shutter.setImageResource(R.drawable.ic_video_stop)
toggle_camera.beInvisible()
showTimer()
} else {
shutter.setImageResource(R.drawable.ic_video_rec)
showToggleCameraIfNeeded()
hideTimer()
}
}
}
fun videoSaved(uri: Uri) {
setupPreviewImage(mIsInPhotoMode)
if (mIsVideoCaptureIntent) {

View File

@ -23,7 +23,7 @@ interface MyPreview {
fun tryTakePicture()
fun toggleRecording(): Boolean
fun toggleRecording()
fun tryInitVideoMode()

View File

@ -793,14 +793,13 @@ class PreviewCameraOne : ViewGroup, SurfaceHolder.Callback, MyPreview {
mIsImageCaptureIntent = isImageCaptureIntent
}
override fun toggleRecording(): Boolean {
override fun toggleRecording() {
if (mIsRecording) {
stopRecording()
initVideoMode()
} else {
startRecording()
}
return mIsRecording
}
private fun getVideoRotation(): Int {
@ -823,6 +822,7 @@ class PreviewCameraOne : ViewGroup, SurfaceHolder.Callback, MyPreview {
mRecorder!!.start()
toggleShutterSound(false)
mIsRecording = true
mActivity!!.setRecordingState(true)
} catch (e: Exception) {
mActivity!!.showErrorToast(e)
releaseCamera()
@ -850,6 +850,7 @@ class PreviewCameraOne : ViewGroup, SurfaceHolder.Callback, MyPreview {
mRecorder = null
mIsRecording = false
mActivity!!.setRecordingState(false)
val file = File(mCurrVideoPath)
if (file.exists() && file.length() == 0L) {

View File

@ -17,6 +17,7 @@ import android.os.Handler
import android.os.HandlerThread
import android.util.DisplayMetrics
import android.util.Size
import android.util.SparseIntArray
import android.view.MotionEvent
import android.view.Surface
import android.view.TextureView
@ -25,6 +26,7 @@ import com.simplemobiletools.camera.activities.MainActivity
import com.simplemobiletools.camera.dialogs.ChangeResolutionDialog
import com.simplemobiletools.camera.extensions.config
import com.simplemobiletools.camera.extensions.getMyCamera
import com.simplemobiletools.camera.extensions.getOutputMediaFile
import com.simplemobiletools.camera.helpers.*
import com.simplemobiletools.camera.interfaces.MyPreview
import com.simplemobiletools.camera.models.FocusArea
@ -34,7 +36,8 @@ import java.util.*
import java.util.concurrent.Semaphore
import java.util.concurrent.TimeUnit
// based on the Android Camera2 sample at https://github.com/googlesamples/android-Camera2Basic
// based on the Android Camera2 photo sample at https://github.com/googlesamples/android-Camera2Basic
// and video sample at https://github.com/googlesamples/android-Camera2Video
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPreview {
private val FOCUS_TAG = "focus_tag"
@ -43,6 +46,20 @@ class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPrevie
private val CLICK_MS = 250
private val CLICK_DIST = 20
private val DEFAULT_ORIENTATIONS = SparseIntArray(4).apply {
append(Surface.ROTATION_0, 90)
append(Surface.ROTATION_90, 0)
append(Surface.ROTATION_180, 270)
append(Surface.ROTATION_270, 180)
}
private val INVERSE_ORIENTATIONS = SparseIntArray(4).apply {
append(Surface.ROTATION_0, 270)
append(Surface.ROTATION_90, 180)
append(Surface.ROTATION_180, 90)
append(Surface.ROTATION_270, 0)
}
private lateinit var mActivity: MainActivity
private lateinit var mTextureView: AutoFitTextureView
@ -58,6 +75,7 @@ class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPrevie
private var mIsFocusSupported = true
private var mIsImageCaptureIntent = false
private var mIsInVideoMode = false
private var mIsRecording = false
private var mUseFrontCamera = false
private var mCameraId = ""
private var mCameraState = STATE_INIT
@ -72,6 +90,7 @@ class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPrevie
private var mCaptureSession: CameraCaptureSession? = null
private var mPreviewRequestBuilder: CaptureRequest.Builder? = null
private var mPreviewRequest: CaptureRequest? = null
private var mMediaRecorder: MediaRecorder? = null
private val mCameraToPreviewMatrix = Matrix()
private val mPreviewToCameraMatrix = Matrix()
private val mCameraOpenCloseLock = Semaphore(1)
@ -177,6 +196,11 @@ class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPrevie
}
}
private fun closeCaptureSession() {
mCaptureSession?.close()
mCaptureSession = null
}
private fun handleZoom(event: MotionEvent) {
val maxZoom = getCameraCharacteristics().get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM) * 10
val sensorRect = getCameraCharacteristics(mCameraId).get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE)
@ -270,9 +294,11 @@ class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPrevie
if (mIsInVideoMode) {
mImageReader = null
mMediaRecorder = MediaRecorder()
} else {
mImageReader = ImageReader.newInstance(currentResolution.width, currentResolution.height, ImageFormat.JPEG, 2)
mImageReader!!.setOnImageAvailableListener(imageAvailableListener, mBackgroundHandler)
mMediaRecorder = null
}
val displaySize = getRealDisplaySize()
@ -300,7 +326,7 @@ class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPrevie
}
val outputSizes = if (mIsInVideoMode) configMap.getOutputSizes(MediaRecorder::class.java) else configMap.getOutputSizes(SurfaceTexture::class.java)
mPreviewSize = chooseOptimalSize(outputSizes, rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth, maxPreviewHeight, currentResolution)
mPreviewSize = chooseOptimalPreviewSize(outputSizes, rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth, maxPreviewHeight, currentResolution)
mTextureView.setAspectRatio(mPreviewSize!!.height, mPreviewSize!!.width)
characteristics.apply {
@ -315,7 +341,7 @@ class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPrevie
}
}
private fun chooseOptimalSize(choices: Array<Size>, textureViewWidth: Int, textureViewHeight: Int, maxWidth: Int, maxHeight: Int, aspectRatio: MySize): Size {
private fun chooseOptimalPreviewSize(choices: Array<Size>, textureViewWidth: Int, textureViewHeight: Int, maxWidth: Int, maxHeight: Int, aspectRatio: MySize): Size {
val bigEnough = ArrayList<Size>()
val notBigEnough = ArrayList<Size>()
val width = aspectRatio.width
@ -400,6 +426,7 @@ class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPrevie
}
try {
closeCaptureSession()
val texture = mTextureView.surfaceTexture!!
texture.setDefaultBufferSize(mPreviewSize!!.width, mPreviewSize!!.height)
@ -416,6 +443,16 @@ class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPrevie
}
}
private fun updatePreview() {
try {
mPreviewRequestBuilder!!.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO)
mCaptureSession!!.setRepeatingRequest(mPreviewRequestBuilder!!.build(), null, mBackgroundHandler)
} catch (e: CameraAccessException) {
e.printStackTrace()
}
}
private val mCaptureCallback = object : CameraCaptureSession.CaptureCallback() {
private fun process(result: CaptureResult) {
when (mCameraState) {
@ -650,6 +687,70 @@ class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPrevie
else -> CameraMetadata.FLASH_MODE_OFF
}
private fun setupMediaRecorder() {
val videoSize = getCurrentResolution()
val currVideoPath = mActivity.getOutputMediaFile(false)
val rotation = mActivity.windowManager.defaultDisplay.rotation
mMediaRecorder!!.apply {
setAudioSource(MediaRecorder.AudioSource.MIC)
setVideoSource(MediaRecorder.VideoSource.SURFACE)
setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
setOutputFile(currVideoPath)
setVideoEncodingBitRate(10000000)
setVideoFrameRate(30)
setVideoSize(videoSize.width, videoSize.height)
setVideoEncoder(MediaRecorder.VideoEncoder.H264)
setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
when (mSensorOrientation) {
90 -> setOrientationHint(DEFAULT_ORIENTATIONS.get(rotation))
270 -> setOrientationHint(INVERSE_ORIENTATIONS.get(rotation))
}
prepare()
}
}
private fun startRecording() {
closeCaptureSession()
setupMediaRecorder()
val texture = mTextureView.surfaceTexture
texture.setDefaultBufferSize(mPreviewSize!!.width, mPreviewSize!!.height)
mPreviewRequestBuilder = mCameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_RECORD)
val surfaces = ArrayList<Surface>()
val previewSurface = Surface(texture)
surfaces.add(previewSurface)
mPreviewRequestBuilder!!.addTarget(previewSurface)
val recorderSurface = mMediaRecorder!!.surface
surfaces.add(recorderSurface)
mPreviewRequestBuilder!!.addTarget(recorderSurface)
val captureCallback = object : CameraCaptureSession.StateCallback() {
override fun onConfigured(session: CameraCaptureSession?) {
mCaptureSession = session
updatePreview()
mIsRecording = true
mActivity.runOnUiThread {
mMediaRecorder?.start()
}
mActivity.setRecordingState(true)
}
override fun onConfigureFailed(session: CameraCaptureSession?) {}
}
mCameraDevice!!.createCaptureSession(surfaces, captureCallback, mBackgroundHandler)
}
private fun stopRecording() {
mIsRecording = false
mMediaRecorder!!.stop()
mMediaRecorder!!.reset()
closeCamera()
openCamera(mTextureView.width, mTextureView.height)
mActivity.setRecordingState(false)
}
override fun setTargetUri(uri: Uri) {
mTargetUri = uri
}
@ -697,8 +798,16 @@ class PreviewCameraTwo : ViewGroup, TextureView.SurfaceTextureListener, MyPrevie
}
}
override fun toggleRecording(): Boolean {
return false
override fun toggleRecording() {
if (mCameraDevice == null || !mTextureView.isAvailable || mPreviewSize == null) {
return
}
if (mIsRecording) {
stopRecording()
} else {
startRecording()
}
}
override fun tryInitVideoMode() {