Использование кеша в ExoPlayer для сохранения потокового видео - PullRequest
1 голос
/ 26 марта 2019

UPDATE:

Я нашел это сообщение , в котором подробно описана та же проблема, что и я. Оказывается, тот факт, что я использую подход Pipe в моем DocumentProvider для потоковой передачи содержимого из DropBox, означает, что ExoPlayer не знает размер файла заранее и поэтому по умолчанию не сохранял его в кеше.

Итак, я закончил тем, что сделал, как я полагаю, автор - для этих ситуаций я создал собственный CacheDataSource, который изменяет переменную DataSpec.flags в методе open () этого класса:

public long open(DataSpec dataSpec) throws IOException {
    try {
        key = cacheKeyFactory.buildCacheKey(dataSpec);
        uri = dataSpec.uri;
        actualUri = getRedirectedUriOrDefault(cache, key, /* defaultUri= */ uri);
        httpMethod = dataSpec.httpMethod;
        if ( !dataSpec.isFlagSet(DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH) ) { // <-- update here
            flags = (dataSpec.flags | DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH);
        } else {
            flags = dataSpec.flags;
        }
        readPosition = dataSpec.position;

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

Но, по крайней мере, теперь мои потоковые файлы сохраняются в кеше.


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

Я просмотрел несколько постов здесь, этот был полезен при выработке общего подхода к записи видео в каталог по моему выбору.

Я заметил, что при обработке URI, который разрешается в моем пользовательском DocumentProvider, кэш, определенный CacheDataSourceFactory, используется только для хранения того, что выглядит как файл «указателя» или «индекса» («cached_content_index.exi»). Просматривая этот файл, я вижу URI видео, передаваемого моим пользовательским DocumentsProvider. Однако фактического видео нет в кеше.

Вот соответствующая часть моего провайдера, это довольно просто:

        // Return a descriptor that will stream the file
        Timber.d("In openDocument of DropboxProvider for Id: %s, streaming from source", documentId);
        ParcelFileDescriptor[] pipe;
        try {
            pipe = ParcelFileDescriptor.createPipe();

            // Get input stream for the pipe
            DbxDownloader downloader = mDbxClient.files().download(fileMetadata.getPathLower(), fileMetadata.getRev());
            new TransferThread(downloader.getInputStream(), new ParcelFileDescriptor.AutoCloseOutputStream(pipe[1]), signal, fileMetadata.getSize()).start();
            return pipe[0];
        } catch (DbxException dbe) {
            Timber.d("Got IDbxException when streaming content: %s", dbe.getMessage());
        } catch (IOException ioe) {
            Timber.d("Got IOException when streaming content: %s", ioe.getMessage());
        } catch (Exception e) {
            Timber.d("Got Exception when streaming content: %s", e.getMessage());
        }
        return null;

И TransferThread:

private static class TransferThread extends Thread {
    final InputStream in;
    final OutputStream out;
    final CancellationSignal signal;
    final long size;

    TransferThread(InputStream in, OutputStream out, CancellationSignal signal, long size) {
        this.in = in;
        this.out = out;
        this.signal = signal;
        this.size = size;
    }
    @Override
    public void run() {
        int biteSize = (8*1024);
        if ( size <= (biteSize * 8) ) {
            biteSize = Math.max( ((int)(size / (biteSize*2))) * (biteSize * 2), biteSize);
        }
        Timber.d("TransferThread: File size is: %s, buffer biteSize set to: %d", InTouchUtils.getFormattedFileSize(size), biteSize);
        byte[] buf = new byte[biteSize];
        int len;
        try {
            while ( ((len=in.read(buf)) >= 0) && (signal == null || !signal.isCanceled()) ) {
                out.write(buf, 0, len);
            }
        } catch (IOException e) {
            // When Glide is used to request a URI where this provider resolves the query,
            // it will close the stream out from under us once it has fetched enough bytes
            // to render a single frame as an image if the if it is to a video, so
            // we swallow that exception here, only logging the error if it isn't that EPIPE
            // (broken pipe due to one end being closed) exception.
            if ( !(e.getMessage().contains("EPIPE"))) {
                Timber.d("TransferThread: Got IOException transferring file: %s", e.getMessage());
            }
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
                if ( out != null ) {
                    out.flush();
                    out.close();
                }
                Timber.d("TransferThread: Finished streaming file.");
            } catch (IOException ioe) {
                Timber.d("TransferThread: Got IOException closing file: %s", ioe.getMessage());

            }
        }
    }
}

Опять же - ExoPlayer, кажется, вполне доволен ParcelFileDescriptor, который он получает от DocumentsProvider в этом случае - он берет переданные ему байты и воспроизводит видео. Я просто не вижу видеофайл в кеше.

Я также попробовал пример потокового видео с моего Google Диска (который использует поставщика документов из коробки от SAF), и на этот раз видео оказалось в кеше.

Поскольку они оба используют один и тот же экземпляр MediaSource - должен быть подход, который использует провайдер Google Docs, чтобы ExoPlayer знал, как поместить полученное потоковое видео в кеш, что не делает мой пользовательский Dropbox DocumentsProvider.

Кто-нибудь знает, как получить исходный код DocumentProvider, который поставляется с SAF, который управляет доступом к Google Docs? Я хотел бы увидеть, что он делает в методе openDocument ().

Является ли тот факт, что поставщик Dropbox использует Pipe в своем ParcelFileDescriptor, чем-то, что не обрабатывает ExoPlayer?

Другие идеи?

...