Захват видео с соотношением сторон 1: 1 на Android

Я пытаюсь разработать приложение для Android, которое будет записывать видео размером 15 секунд 640x640 с помощью MediaRecorder, извлекать все кадры с помощью ffmpeg, применять некоторые художественные фильтры с помощью gpuimage, а затем объединять кадры обратно в видео с помощью ffmpeg.

У меня проблема с записью видео с разрешением 640x640. (Это делает приложение Instagram для Android)

Я попытался использовать setVideoSize (640, 640) MediaRecorder, и выходное видео имеет размер 640x640, но видео выглядит как видео с разрешением 640x480, растянутым по вертикали, чтобы сделать его 640x640. Я предполагаю, что это потому, что 640x640 не является разрешением, возвращаемым поддерживаемым списком разрешений захвата видео устройства. Есть ли способ указать устройству записи мультимедиа поддерживать соотношение сторон при таком масштабировании, чтобы я получал видео, которое было масштабировано с 640x480 до 640x640 путем обрезки по ширине вместо растяжения по высоте?


person Nikhil Mathew    schedule 03.12.2013    source источник
comment
Моя текущая альтернатива - записывать видео с разрешением 640x480, извлекать кадры и обрезать каждый кадр до 480x480, отбрасывая 80 пикселей слева и справа, а затем масштабировать каждый кадр до 640x640. Но это процесс, требующий времени, и если бы я мог сказать MediaRecorder, чтобы он поддерживал соотношение сторон при захвате видео с настраиваемым разрешением, время ожидания пользователям было бы значительно меньше.   -  person Nikhil Mathew    schedule 03.12.2013
comment
Мои настройки MediaRecorder следующие: mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); mediaRecorder.setVideoEncoder(VideoEncoder.H264); mediaRecorder.setOutputFile(Environment.getExternalStorageDirectory().getPath()+‌​"/test.3gp"); mediaRecorder.setMaxDuration(15000); mediaRecorder.setMaxFileSize(50000000); mediaRecorder.setVideoSize(640, 640); mediaRecorder.setVideoFrameRate(30); mediaRecorder.setVideoEncodingBitRate(3000000);   -  person Nikhil Mathew    schedule 03.12.2013
comment
И команду ffmpeg, которую я использую для извлечения кадров из видео: String[] ffmpegCommand = {"ffmpeg", "-i", "test.3gp","-r", "30", "-an", "-s", "640x640", "-qscale:v", "2", "-vsync", "1", "-threads", "4", frame%03d.jpg"};   -  person Nikhil Mathew    schedule 03.12.2013
comment
Странно, что кадрирование + масштаб в ffmpeg имеет значение, когда вы также сталкиваетесь с декодированием, художественными фильтрами и перекодированием. Если вы не используете HW-кодировщик. Вы можете рассмотреть альтернативу - получать кадры предварительного просмотра (640x480 или, может быть, 800x600, если ваша камера поддерживает это), обрезать и применять фильтры и кодировать - все в реальном времени.   -  person Alex Cohn    schedule 04.12.2013
comment
@AlexCohn Спасибо за комментарий. Сначала я пробовал использовать кадры предпросмотра и 640х480. Но даже с кодом для сохранения кадров на SD-карту, независимо от того, сжатый / несжатый, достигнутый FPS не превышает 12 кадров в секунду даже на таких устройствах, как Nexus4 / GalaxyS4. После небольшого поиска в Google мне сказали, что обратный вызов onPreviewFrame () будет вызываться только тогда, когда для всей платформы это удобно. Я не смог найти ни одного случая, когда onPreviewFrame вызывался 30 раз в секунду, даже если реализован пустой обратный вызов. Жизнь была бы намного лучше, если бы она могла выдавать 30 кадров в секунду.   -  person Nikhil Mathew    schedule 04.12.2013
comment
вот способ добиться FPS не хуже, чем MediaRecorder: stackoverflow.com/a/19924579/192373   -  person Alex Cohn    schedule 04.12.2013
comment
Спасибо за ссылку @AlexCohn. Однако я попробовал как предотвращение срабатывания сборки мусора, так и многопоточную камеру. Оба из них, безусловно, улучшили производительность, но не приблизились к производительности записи, которую мы получаем при использовании MediaRecorder. Я всегда проверяю FPS, извлекая все кадры из видео (в котором я записываю быстро движущуюся цель), а затем вручную подсчитываю неповторяющиеся кадры.   -  person Nikhil Mathew    schedule 04.12.2013
comment
@NikhilMathew Реализовал ваш ответ, но получил Unable to find a suitable output format for 'transpose=1' transpose=1: Invalid argument   -  person Kishore Jethava    schedule 09.11.2016


Ответы (1)


В конце концов, я сделал захват с разрешением 640x480, обрезал его до 480x480 при разделении на кадры с помощью ffmpeg, а затем, наконец, когда кадры объединяются обратно в видео с помощью ffmpeg, масштаб увеличивается до 640x640.

String[] ffmpegCommand = {"/sdcard/frames/ffmpeg",
    "-i", "/sdcard/frames/test.3gp",
    "-vf", "crop=480:480:80:0,transpose=1",
    "-r", "30", "-an", "-qscale:v", "2", "-vsync", "1", "-threads", "4",  "/sdcard/frames/image%03d.jpg"};

Транспонирование = 1 требуется, когда приложение работает в портретном режиме.

Примечание. При захвате, чтобы показать только ту часть видео, которая будет включена в окончательное обрезанное видео, я добавил две черные полосы по 80 пикселей в верхней части экрана предварительного просмотра, чтобы скрыть 80 пикселей по обе стороны от видео, которые позже обрезается. Таким образом, пользователь получает то, что видит на превью.

person Nikhil Mathew    schedule 10.12.2013
comment
Можете ли вы предоставить дополнительную информацию / код и т. д., я работаю над той же проблемой - person Muhammad Umar; 21.01.2014
comment
@MuhammadUmar и Nikhil не могли бы вы помочь мне в этом вопросе? - person Kishore Jethava; 30.07.2016