Не могу сохранить видео с водяным знаком

ХЕЛП! Очень долго искал ошибку и в итоге через дэбаг обнаружил "Object is being initialized", есть код:


import android.Manifest
import android.annotation.SuppressLint
import android.content.ContentValues.TAG
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.media.MediaPlayer
import android.os.Bundle
import android.os.Environment
import android.util.Log
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.camera.core.CameraSelector
import androidx.camera.video.FileOutputOptions
import androidx.camera.video.Recording
import androidx.camera.video.VideoRecordEvent
import androidx.camera.view.CameraController
import androidx.camera.view.LifecycleCameraController
import androidx.camera.view.video.AudioConfig
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.BottomSheetScaffold
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.IconButton
import androidx.compose.material3.rememberBottomSheetScaffoldState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.daasuu.mp4compose.FillMode
import com.daasuu.mp4compose.composer.Mp4Composer
import com.daasuu.mp4compose.filter.GlWatermarkFilter
import ru.horekdev.uniade.R
import ru.horekdev.uniade.cameraPreview
import ru.horekdev.uniade.ui.theme.UniadeTheme
import java.io.File


class VideoRecordActivity : ComponentActivity() {
    private var recording: Recording? = null
    private val random = java.util.Random()
    private lateinit var mediaPlayer: MediaPlayer

    private val num = random.nextInt(100000)
    private val file = File(
        Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_MOVIES
        ), "uniade$num.mp4"
    )
    private val textFile = File(file.parentFile!!, "${file.nameWithoutExtension}-t.mp4")
    private val watermarkFile = File(textFile.parentFile!!, "${textFile.nameWithoutExtension}-w.mp4")

    companion object {
        private val CAMERAX_PERMISSIONS = arrayOf(
            Manifest.permission.CAMERA,
            Manifest.permission.RECORD_AUDIO
        )

        lateinit var userName: String
        lateinit var userSurname: String
        lateinit var userDateOfBirth: String
    }

    private fun hasRequiredPermissionsCamera(): Boolean {
        return CAMERAX_PERMISSIONS.all {
            ContextCompat.checkSelfPermission(
                applicationContext,
                it
            ) == PackageManager.PERMISSION_GRANTED
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ActivityCompat.requestPermissions(
            this, arrayOf(arrayOf(CAMERAX_PERMISSIONS).toString()), 0
        )

        setContent {
            UniadeTheme { menu() }
        }
    }

    @OptIn(ExperimentalMaterial3Api::class)
    @Composable
    private fun menu() {
        val scaffoldState = rememberBottomSheetScaffoldState()
        val controller = remember {
            LifecycleCameraController(applicationContext).apply {
                setEnabledUseCases(CameraController.VIDEO_CAPTURE)
            }
        }

        BottomSheetScaffold(
            scaffoldState = scaffoldState,
            sheetPeekHeight = 0.dp,
            sheetContent = {

            }) { paddingValues ->
            Box(
                modifier = Modifier
                    .fillMaxSize()
                    .padding(paddingValues)
            ) {
                cameraPreview(controller = controller, modifier = Modifier.fillMaxSize())

                IconButton(modifier = Modifier.offset(20.dp, 20.dp),
                    onClick = {
                        controller.cameraSelector =
                            if (controller.cameraSelector == CameraSelector.DEFAULT_BACK_CAMERA) {
                                CameraSelector.DEFAULT_FRONT_CAMERA
                            } else {
                                CameraSelector.DEFAULT_BACK_CAMERA
                            }
                    }) {
                    Image(
                        modifier = Modifier
                            .height(30.dp)
                            .width(30.dp),
                        painter = painterResource(id = R.drawable.switch_camera),
                        contentDescription = "switch camera"
                    )
                }

                Row(
                    modifier = Modifier
                        .fillMaxWidth()
                        .align(Alignment.BottomCenter)
                        .padding(16.dp),
                    horizontalArrangement = Arrangement.SpaceAround
                ) {
                    IconButton(onClick = { onRecordVideo(controller) }) {
                        Image(
                            modifier = Modifier
                                .height(30.dp)
                                .width(30.dp),
                            painter = painterResource(id = R.drawable.video_camera),
                            contentDescription = "record video"
                        )
                    }
                }
            }
        }
    }

    @SuppressLint("MissingPermission")
    private fun onRecordVideo(controller: LifecycleCameraController) {
        if (recording != null) {
            recording?.stop()
            recording = null

            return
        }

        if (!hasRequiredPermissionsCamera()) {
            closeContextMenu()
            Toast.makeText(
                applicationContext,
                getString(R.string.your_don_t_accept_camera_permissions), Toast.LENGTH_LONG
            ).show()
            return
        }

        mediaPlayer = MediaPlayer.create(applicationContext, R.raw.phone_video_record)
        mediaPlayer.setVolume(0.1f, 0.1f)
        mediaPlayer.start()

        recording = controller.startRecording(
            FileOutputOptions.Builder(file).build(),
            AudioConfig.create(true),
            ContextCompat.getMainExecutor(applicationContext),
        ) { event ->
            when (event) {
                is VideoRecordEvent.Finalize -> {
                    if (event.hasError()) {
                        recording?.stop()
                        recording = null

                        println(event.cause)
                        Toast.makeText(
                            applicationContext,
                            getString(R.string.toast8), Toast.LENGTH_LONG
                        ).show()
                    } else {
                        addText(file)
                    }
                }
            }
        }
    }

    private fun textToBitmap(text: String): Bitmap {
        val paint = Paint(Paint.ANTI_ALIAS_FLAG)
        paint.textSize = 24.0f
        paint.color = Color.WHITE
        paint.textAlign = Paint.Align.LEFT

        val baseline = -paint.ascent()
        val width = paint.measureText(text) + 0.5f
        val height = baseline + paint.descent() + 0.5f

        val image = Bitmap.createBitmap(width.toInt(), height.toInt(),
            Bitmap.Config.ARGB_8888)
        val canvas = Canvas(image)
        canvas.drawText(text, 0.0f, baseline, paint)

        return image
    }

    private fun addText(file: File) {
        Mp4Composer(file.absolutePath, textFile.absolutePath)
            .fillMode(FillMode.PRESERVE_ASPECT_FIT)
            .filter(
                GlWatermarkFilter(
                    textToBitmap("$userSurname $userName / $userDateOfBirth"),
                    GlWatermarkFilter.Position.RIGHT_BOTTOM
                )
            )
            .listener(object : Mp4Composer.Listener {
                override fun onProgress(progress: Double) {
                    Log.d(TAG, "onProgress = $progress")
                }

                override fun onCurrentWrittenVideoTime(timeUs: Long) {}

                override fun onCompleted() {
                    Log.d(TAG, "onCompleted()")
                    file.delete()
                }

                override fun onCanceled() {
                    Log.d(TAG, "onCanceled")
                }

                override fun onFailed(exception: Exception) {
                    Log.e(TAG, "onFailed()", exception)
                }
            }).start()

        addWatermark(textFile)
    }

    private fun addWatermark(textFile: File) {
        Mp4Composer(textFile.absolutePath, watermarkFile.absolutePath)
            .fillMode(FillMode.PRESERVE_ASPECT_FIT)
            .filter(
                GlWatermarkFilter(
                    BitmapFactory.decodeResource(
                        applicationContext.resources,
                        R.drawable.logo_with_watermark
                    ), GlWatermarkFilter.Position.LEFT_BOTTOM
                )
            )
            .listener(object : Mp4Composer.Listener {
                override fun onProgress(progress: Double) {
                    Log.d(TAG, "onProgress = $progress")
                }

                override fun onCurrentWrittenVideoTime(timeUs: Long) {}

                override fun onCompleted() {
                    Log.d(TAG, "onCompleted()")
                    textFile.delete()
                    Toast.makeText(
                        applicationContext,
                        getString(R.string.toast9), Toast.LENGTH_LONG
                    ).show()
                }

                override fun onCanceled() {
                    Log.d(TAG, "onCanceled")
                }

                override fun onFailed(exception: Exception) {
                    Log.e(TAG, "onFailed()", exception)
                }
            }).start()
    }
}

Ответы (0 шт):