Android захватывает замедленное видео
Как я могу захватить замедленное видео в моем приложении?
Я пытался с помощью
mMediaRecorder.setVideoFrameRate(100);
но приложение вылетает, если я установил значение 20 или более с IllegalStateException
,
Я много исследовал. Нормальное видео составляет от 24 до 30 кадров в секунду. Чтобы увидеть замедленное видео, нам нужно захватить 100-120 кадров в секунду, но устройство этого не позволяет. Но я вижу, что камера по умолчанию в моем устройстве имеет опцию Slow motion.Также несколько приложений в магазине воспроизведения позволяют создавать видеоролики с замедленным движением. Я также пытался установить более высокое значение. setCaptureRate()
, но с этим также захватывается видео в нормальном режиме. В нескольких местах упоминается, что замедленное кино может быть достигнуто через OpenCV/JavaCV
библиотеки, но я не смог понять, как использовать эти библиотеки для захвата замедленного видео в Android?
4 ответа
Из предоставленного вами источника (CamcorderProfile) все, что вам нужно сделать, это УВЕЛИЧИТЬ количество снятых изображений в секунду:
mMediaRecorder.setVideoFrameRate(QUALITY_HIGH_SPEED_LOW);
или же
mMediaRecorder.setVideoFrameRate(QUALITY_HIGH_SPEED_HIGH);
Таким образом, если вы берете 100 изображений в секунду и показывает 25 кадров в секунду, эта записанная секунда занимает 4 секунды, чтобы показать
Пожалуйста, прочтите документацию по классу, который вы используете:
public static final int QUALITY_HIGH_SPEED_LOW
Высокоскоростной ( >= 100 к / с) уровень качества, соответствующий наименьшему доступному разрешению.
Для всех высокоскоростных профилей, определенных ниже ((от QUALITY_HIGH_SPEED_LOW до QUALITY_HIGH_SPEED_2160P), они похожи на обычные профили записи, только с более высокой выходной частотой кадров и скоростью передачи данных. Поэтому, устанавливая эти профили с помощью setProfile(CamcorderProfile) без указания каких-либо других параметров кодирования будет производить высокоскоростное видео, а не замедленное видео с различной частотой кадров захвата и вывода (воспроизведения). Чтобы записывать замедленное видео, приложение должно соответствующим образом установить частоту кадров и скорость вывода видео (воспроизведение) с помощью setVideoFrameRate (int) и setVideoEncodingBitRate (int) на основе коэффициента замедленного движения. Если приложение намеревается выполнить запись видео с помощью кодера MediaCodec, оно должно установить каждое отдельное поле MediaFormat аналогично в соответствии с этим CamcorderProfile.
Хотя я не могу захватывать плавное замедленное видео без рывков, но я могу преобразовать захваченное видео в замедленное, используя ffmpeg, который получается очень плавным и равномерным. Для интеграции FFmpeg в Android мы можем использовать предварительно скомпилированные библиотеки, такие как ffmpeg-android,
Согласно рассматриваемому случаю, мы можем захватывать видео с камеры, а затем конвертировать его в замедленное движение с помощью ffmpeg.
Для создания замедленного видео мы можем использовать следующую команду:
String[] complexCommand = {"-y", "-i", inputFileAbsolutePath, "-filter_complex", "[0:v]setpts=2.0*PTS[v];[0:a]atempo=0.5[a]", "-map", "[v]", "-map", "[a]", "-b:v", "2097k", "-r", "60", "-vcodec", "mpeg4", outputFileAbsolutePath};
Вот,
-y
Перезаписать выходные файлы без запроса
-я
ffmpeg читает из произвольного числа входных "файлов", указанных в опции -i
-карта
Ярлыки выходных ссылок указываются с -map.
-b: v
Установите битрейт видео
-р
Установить частоту кадров
-vcodec
Установите видео кодек
-filter_complex filtergraph
Определите сложный фильтрующий граф, то есть один с произвольным количеством входов и / или выходов. Фильтр работает путем изменения метки времени представления (PTS) каждого видеокадра. Чтобы замедлить видео, необходимо использовать множитель больше 1. Например, если в метках времени 1 и 2 показаны два последовательных кадра, и вы Если вы хотите замедлить видео, эти временные метки должны равняться 2 и 4 соответственно. Таким образом, мы должны умножить их на 2,0.
Вы можете ускорить или замедлить звук с помощью аудио фильтра atemto. Фильтр atempo ограничен использованием значений от 0,5 до 2,0 (поэтому он может замедлять его не менее чем до половины первоначальной скорости и увеличивать скорость не более чем в два раза вход). Чтобы замедлить звук до половины его скорости, мы должны использовать значение atempo 0,5 .
Посмотрите это руководство по редактору видео fffmpeg, которое я написал в своем блоге, которое включает создание замедленного видео и полный код для этого руководства здесь.
То, что работало для меня, должно было повысить скорость захвата mMediaRecorder
лайк:
mMediaRecorder.setVideoFrameRate(profile.videoFrameRate / 2);
mMediaRecorder.setVideoEncodingBitRate(profile.videoBitRate / 2);
mMediaRecorder.setCaptureRate(profile.videoFrameRate);
куда profile
это CamcorderProfile
установить с QUALITY_HIGH
(Я не могу иметь больше, так как я использую LG G2, API 19).
Здесь, в моем случае,profile.videoFrameRate
равен 30
Подробнее о setCaptureRate
в официальной документации:
Установите частоту захвата видеокадров. Это можно использовать для установки частоты захвата видеокадров, отличной от частоты воспроизведения записанного видео. Этот метод также устанавливает режим записи в промежуток времени. При покадровой записи видео записывается только видео. Параметры, связанные со звуком, игнорируются, когда начинается сеанс интервальной записи, если приложение устанавливает их.
Результат записи видео в два раза дольше первоначального захвата. Однако установка скорости захвата отключает звук. В моем случае моя максимальная частота кадров составляет 30 кадров в секунду, а затем она воспроизводится со скоростью 15 кадров в секунду.
Надеюсь, поможет.
Попробуйте этот код. Это поможет...
myCamera = getCameraInstance();
mediaRecorder = new MediaRecorder();
myCamera.unlock();
mediaRecorder.setCamera(myCamera);
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
mediaRecorder.setPreviewDisplay(mSurfaceView.getHolder().getSurface());