Android 视频剪辑库

Android video trimming library

我正在做视频剪辑并使用 k4l-video-trimmer 库。我有问题。我已经下载了最新的代码并将其集成到 Android Studio 中。当我 select 一个视频时,k4l-video-trimmer 成功地准备了视频并正确显示了视频信息和快照。我已将最大持续时间设置为 10 秒,但是当移动进度条以在特定持续时间裁剪视频时,屏幕上显示的裁剪持续时间(01:21 秒 - 01:31 秒)10 秒将变为(01:21 秒 - 01:36 秒) 变成 15 秒的持续时间,这是一个问题,当我裁剪视频时,它会裁剪 23 秒。我不知道如何解决这个问题。请帮我解决这个问题

您必须实施 MediaRecorder.OnInfoListener 才能在 10 秒时手动停止录制。一旦停止,MediaRecorder 将返回到初始状态,必须重新进行设置才能重新开始录制。

public class VideoCapture extends Activity implements MediaRecorder.OnInfoListener { 

   public void startVideoRecording() {
      // Normal MediaRecorder Setup
      recorder.setMaxDuration(10000); // 10 seconds
      recorder.setOnInfoListener(this); // very important
   }

   public void onInfo(MediaRecorder mrc, int mri, int extra) { 
      if (mri == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
         Log.v("VIDEOCAPTURE","10 seconds"); 
         mrc.stop();
      }
   }
}

现在,对于进度条,您可以使用 Timer

//fires once a second, decrease this to fire more frequently
private static final int TIMER_FREQ = 1000; 

final ProgressBar progressBar = new ProgressBar(this); //where this is a Context
progressBar.setMax(10000);

Timer progressBarAdvancer = new Timer();
progressBarAdvancer.scheduleAtFixedRate(new TimerTask() {

        public void run() {
            progressBar.setProgress(progressBar.getProgress() + TIMER_FREQ);
        }
    },
    0, //Delay before first execution
    TIMER_FREQ); 

通过这样做,progressBar 在独立于记录的线程上运行,但将在要求的 10 秒内完成。此时您可以停止录制并执行其余操作。

此外,您还可以使用 Video Trimmer 基于“k4l-video-trimmer”的库来处理 k4l-video-trimmer 上的各种问题。

可以使用 mobile-ffmpeg 支持 API 级别 16+

fun scaleVideo(path: String, destinationFilePath: String) {
    _loaderVisisble.value = true
    viewModelScope.launch {
        val cmd = arrayOf(
            "-i",
            path,
            "-vf",
            "scale=576:1024:force_original_aspect_ratio=decrease",
            destinationFilePath
        )
        Log.v("str_Cmd", cmd.toString() + "")
        val status = executeCommand(cmd)
        when (status) {
            FFmpeg.RETURN_CODE_SUCCESS -> {
                _loaderVisisble.value = false
                val mergedFile = File(destinationFilePath)
                Log.v(
                    "target_file_size",
                    (mergedFile.length() / 1024).toString().toInt().toString() + ""
                )
                onVideoScaleListener.postValue(destinationFilePath)
            }
            FFmpeg.RETURN_CODE_CANCEL -> {
                _loaderVisisble.value = false
            }
            else -> {
                _loaderVisisble.value = false
            }
        }
    }
}


private suspend fun executeCommand(cmd: Array<String>): Int {
    var status = -1
    withContext(Dispatchers.Default) {
        val rc = FFmpeg.execute(cmd)
        when (rc) {
            FFmpeg.RETURN_CODE_SUCCESS -> {
                Log.i(
                    Config.TAG,
                    "Command execution completed successfully."
                )
            }
            FFmpeg.RETURN_CODE_CANCEL -> {
                Log.i(
                    Config.TAG,
                    "Command execution cancelled by user."
                )
            }
            else -> {
                Log.i(
                    Config.TAG,
                    String.format(
                        "Command execution failed with rc=%d and the output below.",
                        rc
                    )
                )
            }
        }
        status = rc
    }
    return status
}