From fe9d9d7298de2ce4a118ca0827484a5e472e12ad Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Tue, 28 Nov 2023 18:59:01 +0100 Subject: [PATCH] debug: current stand trying to make ffmpeg to work --- .../alibi/helpers/AudioBatchesFolder.kt | 11 ++--- .../myzel394/alibi/helpers/BatchesFolder.kt | 8 +--- .../myzel394/alibi/helpers/MediaConverter.kt | 4 +- .../alibi/helpers/VideoBatchesFolder.kt | 15 +++---- .../alibi/services/RecorderService.kt | 8 ++-- .../alibi/services/VideoRecorderService.kt | 40 ++++++++++++++----- .../organisms/RecordingStatus.kt | 5 +-- .../alibi/ui/models/AudioRecorderModel.kt | 16 +------- .../alibi/ui/models/BaseRecorderModel.kt | 17 ++++---- .../alibi/ui/models/VideoRecorderModel.kt | 4 +- .../alibi/ui/screens/AudioRecorderScreen.kt | 2 +- .../app/myzel394/alibi/ui/screens/POCVideo.kt | 19 ++++++++- 12 files changed, 80 insertions(+), 69 deletions(-) diff --git a/app/src/main/java/app/myzel394/alibi/helpers/AudioBatchesFolder.kt b/app/src/main/java/app/myzel394/alibi/helpers/AudioBatchesFolder.kt index e49e689..1873867 100644 --- a/app/src/main/java/app/myzel394/alibi/helpers/AudioBatchesFolder.kt +++ b/app/src/main/java/app/myzel394/alibi/helpers/AudioBatchesFolder.kt @@ -56,15 +56,12 @@ class AudioBatchesFolder( } companion object { - fun viaInternalFolder(context: Context): BatchesFolder { - return AudioBatchesFolder(context, BatchType.INTERNAL) - } + fun viaInternalFolder(context: Context) = AudioBatchesFolder(context, BatchType.INTERNAL) - fun viaCustomFolder(context: Context, folder: DocumentFile): BatchesFolder { - return AudioBatchesFolder(context, BatchType.CUSTOM, folder) - } + fun viaCustomFolder(context: Context, folder: DocumentFile) = + AudioBatchesFolder(context, BatchType.CUSTOM, folder) - fun importFromFolder(folder: String, context: Context): BatchesFolder = when (folder) { + fun importFromFolder(folder: String, context: Context) = when (folder) { "_'internal" -> viaInternalFolder(context) else -> viaCustomFolder(context, DocumentFile.fromTreeUri(context, Uri.parse(folder))!!) } diff --git a/app/src/main/java/app/myzel394/alibi/helpers/BatchesFolder.kt b/app/src/main/java/app/myzel394/alibi/helpers/BatchesFolder.kt index c801e6e..c9c2827 100644 --- a/app/src/main/java/app/myzel394/alibi/helpers/BatchesFolder.kt +++ b/app/src/main/java/app/myzel394/alibi/helpers/BatchesFolder.kt @@ -21,7 +21,7 @@ abstract class BatchesFolder( fun initFolders() { when (type) { - BatchType.INTERNAL -> getFolder(context).mkdirs() + BatchType.INTERNAL -> getInternalFolder().mkdirs() BatchType.CUSTOM -> { if (customFolder!!.findFile(subfolderName) == null) { customFolder!!.createDirectory(subfolderName) @@ -35,7 +35,7 @@ abstract class BatchesFolder( } fun getInternalFolder(): File { - return getFolder(context) + return File(context.filesDir, subfolderName) } fun getCustomDefinedFolder(): DocumentFile { @@ -189,9 +189,5 @@ abstract class BatchesFolder( INTERNAL, CUSTOM, } - - companion object { - fun getFolder(context: Context) = File(context.filesDir, RECORDER_SUBFOLDER_NAME) - } } diff --git a/app/src/main/java/app/myzel394/alibi/helpers/MediaConverter.kt b/app/src/main/java/app/myzel394/alibi/helpers/MediaConverter.kt index ec2e465..d2dd324 100644 --- a/app/src/main/java/app/myzel394/alibi/helpers/MediaConverter.kt +++ b/app/src/main/java/app/myzel394/alibi/helpers/MediaConverter.kt @@ -67,9 +67,9 @@ class MediaConverter { val listFile = createTempFile(inputFiles.joinToString("\n", prefix = "file ")) val command = - "-protocol_whitelist saf,concat,content,file,subfile" + - " -f concat" + + " -f concat" + " -y" + + " -safe 0" + " -i ${listFile.absolutePath}" + " -c copy" + extraCommand + diff --git a/app/src/main/java/app/myzel394/alibi/helpers/VideoBatchesFolder.kt b/app/src/main/java/app/myzel394/alibi/helpers/VideoBatchesFolder.kt index db84f1f..ba01cb9 100644 --- a/app/src/main/java/app/myzel394/alibi/helpers/VideoBatchesFolder.kt +++ b/app/src/main/java/app/myzel394/alibi/helpers/VideoBatchesFolder.kt @@ -53,17 +53,14 @@ class VideoBatchesFolder( } companion object { - fun viaInternalFolder(context: Context): BatchesFolder { - return VideoBatchesFolder(context, BatchType.INTERNAL) - } + fun viaInternalFolder(context: Context) = VideoBatchesFolder(context, BatchType.INTERNAL) - fun viaCustomFolder(context: Context, folder: DocumentFile): BatchesFolder { - return VideoBatchesFolder(context, BatchType.CUSTOM, folder) - } + fun viaCustomFolder(context: Context, folder: DocumentFile) = + VideoBatchesFolder(context, BatchType.CUSTOM, folder) - fun importFromFolder(folder: String, context: Context): BatchesFolder = when (folder) { - "_'internal" -> AudioBatchesFolder.viaInternalFolder(context) - else -> AudioBatchesFolder.viaCustomFolder( + fun importFromFolder(folder: String, context: Context) = when (folder) { + "_'internal" -> viaInternalFolder(context) + else -> viaCustomFolder( context, DocumentFile.fromTreeUri(context, Uri.parse(folder))!! ) diff --git a/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt b/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt index e80c1ff..e550dfa 100644 --- a/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt +++ b/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt @@ -162,12 +162,14 @@ abstract class RecorderService : LifecycleService() { changeState(RecorderState.RECORDING) } + fun stopRecording() { + changeState(RecorderState.IDLE) + stop() + } + override fun onDestroy() { super.onDestroy() - stop() - changeState(RecorderState.IDLE) - stopForeground(STOP_FOREGROUND_REMOVE) NotificationManagerCompat.from(this) .cancel(NotificationHelper.RECORDER_CHANNEL_NOTIFICATION_ID) diff --git a/app/src/main/java/app/myzel394/alibi/services/VideoRecorderService.kt b/app/src/main/java/app/myzel394/alibi/services/VideoRecorderService.kt index d593e0c..e5334ed 100644 --- a/app/src/main/java/app/myzel394/alibi/services/VideoRecorderService.kt +++ b/app/src/main/java/app/myzel394/alibi/services/VideoRecorderService.kt @@ -1,6 +1,7 @@ package app.myzel394.alibi.services import android.annotation.SuppressLint +import android.util.Range import androidx.camera.core.Camera import androidx.camera.core.CameraSelector import androidx.camera.lifecycle.ProcessCameraProvider @@ -38,6 +39,8 @@ class VideoRecorderService : // Used to listen and check if the camera is available private var _cameraAvailableListener = CompletableDeferred() + private var selectedCamera: CameraSelector = CameraSelector.DEFAULT_BACK_CAMERA + // Runs a function in the main thread private fun runInMain(callback: () -> Unit) { val mainHandler = ContextCompat.getMainExecutor(this) @@ -45,6 +48,23 @@ class VideoRecorderService : mainHandler.execute(callback) } + private fun buildRecorder() = Recorder.Builder() + .setQualitySelector(settings.quality) + .apply { + if (settings.targetVideoBitRate != null) { + setTargetVideoEncodingBitRate(settings.targetVideoBitRate!!) + } + } + .build() + + private fun buildVideoCapture(recorder: Recorder) = VideoCapture.Builder(recorder) + .apply { + if (settings.targetFrameRate != null) { + setTargetFrameRate(Range(settings.targetFrameRate!!, settings.targetFrameRate!!)) + } + } + .build() + // Open the camera. // Used to open it for a longer time, shouldn't be called when pausing / resuming. // This should only be called when starting a recording. @@ -53,16 +73,13 @@ class VideoRecorderService : ProcessCameraProvider.getInstance(this@VideoRecorderService).get() } - val recorder = Recorder.Builder() - .setQualitySelector(settings.quality) - .build() - videoCapture = VideoCapture.Builder(recorder) - .build() + val recorder = buildRecorder() + videoCapture = buildVideoCapture(recorder) runInMain { camera = cameraProvider!!.bindToLifecycle( this, - CameraSelector.DEFAULT_BACK_CAMERA, + selectedCamera, videoCapture ) @@ -74,7 +91,7 @@ class VideoRecorderService : // Used to close it finally, shouldn't be called when pausing / resuming. // This should only be called after recording has finished. private fun closeCamera() { - clearOldVideoRecording() + stopActiveRecording() runCatching { cameraProvider?.unbindAll() @@ -99,10 +116,8 @@ class VideoRecorderService : closeCamera() } - private fun clearOldVideoRecording() { - runCatching { - activeRecording?.stop() - } + private fun stopActiveRecording() { + activeRecording?.stop() } @SuppressLint("MissingPermission") @@ -143,11 +158,13 @@ class VideoRecorderService : type = RecordingInformation.Type.VIDEO, ) + // TODO: Save camera selector as it doesn't make sense to change the camera midway data class Settings( override val maxDuration: Long, override val intervalDuration: Long, val folder: String? = null, val targetVideoBitRate: Int? = null, + val targetFrameRate: Int? = null, val quality: QualitySelector = QualitySelector.from(Quality.HIGHEST), ) : IntervalRecorderService.Settings( maxDuration = maxDuration, @@ -172,6 +189,7 @@ class VideoRecorderService : intervalDuration = appSettings.audioRecorderSettings.intervalDuration, folder = appSettings.audioRecorderSettings.saveFolder, targetVideoBitRate = appSettings.videoRecorderSettings.targetedVideoBitRate, + targetFrameRate = appSettings.videoRecorderSettings.targetFrameRate, quality = appSettings.videoRecorderSettings.getQualitySelector() ?: QualitySelector.from( Quality.HIGHEST diff --git a/app/src/main/java/app/myzel394/alibi/ui/components/AudioRecorder/organisms/RecordingStatus.kt b/app/src/main/java/app/myzel394/alibi/ui/components/AudioRecorder/organisms/RecordingStatus.kt index ac2b163..d76154d 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/components/AudioRecorder/organisms/RecordingStatus.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/components/AudioRecorder/organisms/RecordingStatus.kt @@ -26,7 +26,6 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import app.myzel394.alibi.dataStore import app.myzel394.alibi.db.AppSettings -import app.myzel394.alibi.helpers.AudioRecorderExporter import app.myzel394.alibi.ui.components.AudioRecorder.atoms.DeleteButton import app.myzel394.alibi.ui.components.AudioRecorder.atoms.MicrophoneDisconnectedDialog import app.myzel394.alibi.ui.components.AudioRecorder.atoms.MicrophoneReconnectedDialog @@ -106,7 +105,7 @@ fun RecordingStatus( ) { DeleteButton( onDelete = { - audioRecorder.stopRecording(context) + //audioRecorder.stopRecording(context) audioRecorder.batchesFolder!!.deleteRecordings(); } ) @@ -136,7 +135,7 @@ fun RecordingStatus( SaveButton( onSave = { runCatching { - audioRecorder.stopRecording(context) + //audioRecorder.stopRecording(context) } audioRecorder.onRecordingSave() } diff --git a/app/src/main/java/app/myzel394/alibi/ui/models/AudioRecorderModel.kt b/app/src/main/java/app/myzel394/alibi/ui/models/AudioRecorderModel.kt index 291dd84..0395f8c 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/models/AudioRecorderModel.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/models/AudioRecorderModel.kt @@ -1,32 +1,20 @@ package app.myzel394.alibi.ui.models -import android.content.ComponentName import android.content.Context -import android.content.Intent -import android.content.ServiceConnection import android.net.Uri -import android.os.IBinder import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue -import androidx.core.content.ContextCompat import androidx.documentfile.provider.DocumentFile -import androidx.lifecycle.ViewModel import app.myzel394.alibi.db.AppSettings import app.myzel394.alibi.db.RecordingInformation -import app.myzel394.alibi.enums.RecorderState import app.myzel394.alibi.helpers.AudioBatchesFolder -import app.myzel394.alibi.helpers.AudioRecorderExporter -import app.myzel394.alibi.helpers.BatchesFolder import app.myzel394.alibi.services.AudioRecorderService -import app.myzel394.alibi.services.IntervalRecorderService -import app.myzel394.alibi.services.RecorderNotificationHelper -import app.myzel394.alibi.services.RecorderService -import kotlinx.serialization.json.Json import app.myzel394.alibi.ui.utils.MicrophoneInfo class AudioRecorderModel : - BaseRecorderModel() { + BaseRecorderModel() { + override var batchesFolder: AudioBatchesFolder? = null override val intentClass = AudioRecorderService::class.java var amplitudes by mutableStateOf>(emptyList()) diff --git a/app/src/main/java/app/myzel394/alibi/ui/models/BaseRecorderModel.kt b/app/src/main/java/app/myzel394/alibi/ui/models/BaseRecorderModel.kt index 1b3c104..13e5e34 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/models/BaseRecorderModel.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/models/BaseRecorderModel.kt @@ -19,9 +19,10 @@ import app.myzel394.alibi.services.AudioRecorderService import app.myzel394.alibi.services.IntervalRecorderService import app.myzel394.alibi.services.RecorderNotificationHelper import app.myzel394.alibi.services.RecorderService +import kotlinx.coroutines.delay import kotlinx.serialization.json.Json -abstract class BaseRecorderModel> : +abstract class BaseRecorderModel, B : BatchesFolder?> : ViewModel() { protected abstract val intentClass: Class @@ -44,7 +45,7 @@ abstract class BaseRecorderModel Unit = {} var onError: () -> Unit = {} - var batchesFolder: BatchesFolder? = null + abstract var batchesFolder: B private var notificationDetails: RecorderNotificationHelper.NotificationDetails? = null @@ -69,6 +70,8 @@ abstract class BaseRecorderModel() { + BaseRecorderModel() { + override var batchesFolder: VideoBatchesFolder? = null override val intentClass = VideoRecorderService::class.java override fun onServiceConnected(service: VideoRecorderService) { diff --git a/app/src/main/java/app/myzel394/alibi/ui/screens/AudioRecorderScreen.kt b/app/src/main/java/app/myzel394/alibi/ui/screens/AudioRecorderScreen.kt index 09f0866..ed6f354 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/screens/AudioRecorderScreen.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/screens/AudioRecorderScreen.kt @@ -178,7 +178,7 @@ fun AudioRecorderScreen( audioRecorder.onError = { saveAsLastRecording() - audioRecorder.stopRecording(context) + //audioRecorder.stopRecording(context) showRecorderError = true } diff --git a/app/src/main/java/app/myzel394/alibi/ui/screens/POCVideo.kt b/app/src/main/java/app/myzel394/alibi/ui/screens/POCVideo.kt index 28930c4..4440718 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/screens/POCVideo.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/screens/POCVideo.kt @@ -9,6 +9,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier @@ -16,6 +17,8 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import app.myzel394.alibi.db.AppSettings import app.myzel394.alibi.ui.models.VideoRecorderModel +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch @SuppressLint("NewApi") @Composable @@ -29,6 +32,8 @@ fun POCVideo( mutableStateOf(false) } + val scope = rememberCoroutineScope() + Box( modifier = Modifier .fillMaxSize() @@ -38,9 +43,19 @@ fun POCVideo( if (!started) { videoRecorder.startRecording(context, settings) } else { - videoRecorder.stopRecording(context) + scope.launch { + val information = videoRecorder.recorderService!!.getRecordingInformation() + val batchesFolder = videoRecorder.batchesFolder!! + videoRecorder.stopRecording(context) - val folder = "content://media/external/video/media/DCIM/Recordings" + delay(5000) + + batchesFolder.concatenate( + recordingStart = information.recordingStart, + extension = information.fileExtension, + disableCache = true, + ) + } } started = !started