Задний план
Мы хотим, чтобы пользователь мог выбрать видео из любого приложения, а затем обрезать видео до 5 секунд.
Эта проблема
Для выбора Uri у нас все работает нормально (решение доступно здесь).
Что касается самой обрезки, мы не смогли найти ни одной хорошей библиотеки с разрешающей лицензией, кроме одной под названием "k4l-video-trimmer" . Библиотека «FFmpeg», например, считается неразрешенной, поскольку она использует GPLv3, которая требует, чтобы приложение, использующее ее, также было с открытым исходным кодом. Кроме того, как я читал, он занимает довольно много (около 9 МБ).
К сожалению, эта библиотека (k4l-video-trimmer) очень старая и не обновлялась годами, поэтому мне пришлось ее разветвить (здесь), чтобы правильно с этим справиться. Для обрезки используется библиотека с открытым исходным кодом под названием "mp4parser".
Проблема в том, что эта библиотека, по-видимому, может обрабатывать только файлы, а не Uri
или InputStream
, поэтому даже образец может аварийно завершать работу при выборе элементов, которые недоступны, как обычный файл, или даже имеют пути, которые он не может обработать. . Я знаю, что во многих случаях можно получить путь к файлу, но во многих других случаях это невозможно, и я также знаю, что можно просто скопировать файл (здесь), но это не очень хорошее решение, так как файл может быть большим и занимать много места, даже если он уже доступен.
Что я пробовал
Есть 2 места, где библиотека использует файл:
В файле «K4LVideoTrimmer» в функции «setVideoURI», которая просто показывает размер файла. Здесь решение довольно простое, основанное на документации Google< /сильный>а>:
public void setVideoURI(final Uri videoURI) { mSrc = videoURI; if (mOriginSizeFile == 0) { final Cursor cursor = getContext().getContentResolver().query(videoURI, null, null, null, null); if (cursor != null) { int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE); cursor.moveToFirst(); mOriginSizeFile = cursor.getLong(sizeIndex); cursor.close(); mTextSize.setText(Formatter.formatShortFileSize(getContext(), mOriginSizeFile)); } } ...
В файле «TrimVideoUtils», в «startTrim», который вызывает функцию «genVideoUsingMp4Parser». Там он вызывает библиотеку «mp4parser», используя:
Movie movie = MovieCreator.build(new FileDataSourceViaHeapImpl(src.getAbsolutePath()));
Там написано, что они используют
FileDataSourceViaHeapImpl
(из библиотеки "mp4parser"), чтобы избежать OOM на Android, поэтому я решил остаться с ним.Дело в том, что для него есть 4 CTORS, все ожидают какой-то вариации файла: File, filePath, FileChannel , FileChannel+fileName .
Вопросы
- Есть ли способ преодолеть это?
Может быть, реализовать FileChannel
и смоделировать реальный файл, используя ContentResolver
и Uri
? Я думаю, это возможно, даже если это означает повторное открытие InputStream при необходимости...
Чтобы увидеть, что у меня получилось, вы можете клонировать проект здесь. Просто знайте, что он не выполняет обрезку, так как код для этого в файле «K4LVideoTrimmer» закомментирован:
//TODO handle trimming using Uri
//TrimVideoUtils.startTrim(file, getDestinationPath(), mStartPosition, mEndPosition, mOnTrimVideoListener);
- Возможно, есть лучшая альтернатива этой библиотеке обрезки, которая также является разрешающей (например, имеется в виду лицензия Apache2/MIT)? Тот, у которого нет этой проблемы? Или, может быть, даже что-то из самого фреймворка Android? Я думаю, что класс MediaMuxer может помочь (как написано < a href="https://stackoverflow.com/a/44653626/878126">здесь), но я думаю, что ему может понадобиться API 26, а нам нужно обрабатывать API 21 и над...
РЕДАКТИРОВАТЬ:
Я думал, что нашел решение, используя другое решение для самой обрезки, и написал об этом здесь< /a>, но, к сожалению, он не может обрабатывать некоторые входные видео, в то время как библиотека mp4parser
может их обрабатывать.
Пожалуйста, дайте мне знать, возможно ли изменить mp4parser
для обработки таких входных видео, даже если они из Uri, а не из файла (без обходного пути простого копирования в видеофайл).