Используя mp4parser, как я могу обрабатывать видео, взятые из Uri и ContentResolver? - PullRequest
0 голосов
/ 03 февраля 2019

Фон

Мы хотим, чтобы пользователь мог выбрать видео из любого приложения, а затем обрезать видео максимум до 5 секунд.

Проблема

Чтобы получить Uri, который мы выбрали, он работает нормально (доступно решение здесь ).

Что касается самой обрезки, мы не смогли найти ни одной хорошей библиотеки, которая имеет разрешительную лицензию, за исключением одной под названием "k4l-video-trimmer" .Например, библиотека «FFmpeg» считается недопустимой, поскольку она использует GPLv3, что требует, чтобы приложение, использующее ее, также было открытым исходным кодом.Кроме того, как я читал, это занимает довольно много (около 9 МБ).

К сожалению, эта библиотека (k4l-video-trimmer) очень старая и не обновлялась годами, поэтому мне пришлосьраскошелитесь ( здесь ), чтобы справиться с этим красиво.Для обрезки используется библиотека с открытым исходным кодом "mp4parser" .

Проблема в том, что эта библиотека может обрабатывать только файлы, а неUri или InputStream, поэтому даже образец может аварийно завершить работу при выборе элементов, которые недоступны, как обычный файл, или даже иметь пути, которые он не может обработать.Я знаю, что во многих случаях возможно получить путь к файлу, но во многих других случаях это не так, и я также знаю, что можно просто скопировать файл ( здесь ), но это не очень хорошее решение, так как файл может быть большим и занимать много места, даже если он уже доступен.

Что я пробовал

Есть 2указывает, что библиотека использует файл:

  1. В файле "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));
            }
        }
     ...
    
  2. В файле "TrimVideoUtils", в файле "startTrim", которыйвызывает функцию "genVideoUsingMp4Parser".Там она вызывает библиотеку «mp4parser», используя:

    Movie movie = MovieCreator.build(new FileDataSourceViaHeapImpl(src.getAbsolutePath()));
    

    Она говорит, что они используют FileDataSourceViaHeapImpl (из библиотеки «mp4parser»), чтобы избежать OOM на Android, поэтому я решил остаться с ней.

    Дело в том, что для этого существует 4 CTORS, все ожидают некоторого изменения файла: File, filePath, FileChannel, FileChannel + fileName.

Вопросы

  1. Есть ли способ преодолеть это?

Может быть, реализовать FileChannel и моделировать реальный файл, используя ContentResolver и Uri?Я предполагаю, что это возможно, даже если это означает повторное открытие InputStream при необходимости ...

Чтобы увидеть, что я получил, вы можете клонировать проект здесь .Просто знайте, что это не делает никакой обрезки, поскольку код для этого в файле "K4LVideoTrimmer" прокомментирован:

//TODO handle trimming using Uri
//TrimVideoUtils.startTrim(file, getDestinationPath(), mStartPosition, mEndPosition, mOnTrimVideoListener);
Возможно, есть лучшая альтернатива этой библиотеке обрезки, которая также является разрешающей (например, имеется в виду лицензии Apache2 / MIT)?Тот, у которого нет этой проблемы?Или, может быть, даже что-то из самого Android Framework?Я думаю, что класс MediaMuxer мог бы помочь (как написано здесь ), но я думаю, что для этого может потребоваться API 26, в то время как нам нужно обрабатыватьAPI 21 и выше ...

РЕДАКТИРОВАТЬ:

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

Пожалуйста, дайте мне знать, если возможно изменить mp4parserобрабатывать такие входные видео, даже если они из Uri, а не из File (без обходного пути простого копирования в видеофайл).

1 Ответ

0 голосов
/ 13 февраля 2019

Прежде всего, предостережение: я не знаком с библиотекой mp4parser, но ваш вопрос выглядел интересным, поэтому я посмотрел.

Я думаю, стоит взглянуть на один из классов, которые, как говорят комментарии кода,«в основном для тестирования».InMemRandomAccessSourceImpl.Чтобы создать Movie из любого URI, код должен выглядеть следующим образом:

try {
    InputStream  inputStream = getContentResolver().openInputStream(uri);
    Log.e("InputStream Size","Size " + inputStream);
    int  bytesAvailable = inputStream.available();
    int bufferSize = Math.min(bytesAvailable, MAX_BUFFER_SIZE);
    final byte[] buffer = new byte[bufferSize];

    int read = 0;
    int total = 0;
    while ((read = inputStream.read(buffer)) !=-1 ) {
        total += read;
    }
    if( total < bytesAvailable ){
        Log.e(TAG, "Read from input stream failed")
        return;
    }
    //or try inputStream.readAllBytes() if using Java 9
    inputStream.close();

    ByteBuffer bb = ByteBuffer.wrap(buffer);
    Movie m2 = MovieCreator.build(new ByteBufferByteChannel(bb),
        new InMemRandomAccessSourceImpl(bb), "inmem");

} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

Но я бы сказал, что между тем, чего вы хотите достичь, и подходом, который использует синтаксический анализатор, возникает некоторый конфликт.Это зависит от локальных файлов, чтобы избежать больших накладных расходов памяти, и произвольный доступ к байтам может быть сделан только при наличии всего набора данных, что отличается от потокового подхода.

Это потребует буферизации как минимум количества данных, требуемых для вашего клипа, за один раз, прежде чем парсер получит буфер.Это может быть полезным для вас, если вы хотите захватывать короткие участки, и буферизация не слишком громоздка.Вы можете быть подвержены исключениям ввода-вывода и тому подобное, если чтение из InputStream имеет проблемы, особенно если это удаленный контент, тогда как вы действительно не ожидаете этого с файлом в современной системе.

Также необходимо рассмотреть MemoryFile, который предоставляет файлоподобный объект с резервной копией в виде пепла.Я думаю, что как-то можно было бы поработать.

...