Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build MediaSource from InputStream (without any Uri) #4149

Closed
petersamokhin opened this issue Apr 18, 2018 · 9 comments
Closed

Build MediaSource from InputStream (without any Uri) #4149

petersamokhin opened this issue Apr 18, 2018 · 9 comments
Assignees
Labels

Comments

@petersamokhin
Copy link

petersamokhin commented Apr 18, 2018

I'm working with own binary format. Some parts of this file contains bytes of media files. I can't "extract" them and provide Uri to ExoPlayer (it works, but it impractical).
Also I can't read all these parts to memory and provide byte array to ExoPlayer (and there no ability to do this too, because I saw ByteArrayDataSource, but can't create any MediaSource from this).

I created my InputStream that providing fixed count of bytes from necessary offset of file (without reading all file to memory). Also I created InputStreamDataSource extends DataSource, that using my InputStream.

So question is, how to create MediaSource that will use my DataSource? All MediaSource implementations requires Uri.

@petersamokhin petersamokhin changed the title Build MediaSource from InputStream (without Uri) Build MediaSource from InputStream (without any Uri) Apr 18, 2018
@AquilesCanta
Copy link
Contributor

Hi, could you clarify why implementing your own Extractor is not enough? If your binary format is just a stream of bytes, then I am inclined to think that's the way to go. Implementing a media source is an overkill. On the other hand, the DataSource allows you to implement a custom way to fetch the bytes, so it should work with any media format: custom or not.

I saw ByteArrayDataSource, but can't create any MediaSource from this

Could you clarify what this means?

So question is, how to create MediaSource that will use my DataSource? All MediaSource implementations requires Uri.

Yes, you need both a Uri and a DataSource. You need a Uri to create the DataSpec that the DataSource takes through open().

In any case, implementing a media source is not different from implementing any other interface. From your description of the issue, the ExtractorMediaSource should fit well, since there is no adaptation going on. So if you are sure you cannot use ExtractorMediaSource with your own implementation of Extractor, then using it as a base is the way to go, in my opinion.

@AquilesCanta AquilesCanta self-assigned this Apr 19, 2018
@AquilesCanta
Copy link
Contributor

Closing due to lack of activity.

@isabsent
Copy link

isabsent commented May 7, 2018

@petersamokhin: I have the same requirement - to play media from encrypted container (local or cloud). Do you have any progress with your task?

P.S.:

I can't "extract" them and provide Uri to ExoPlayer...

Я подозреваю, что нужно реализовать свой ContentProvider, который по указанному Вами Uri позволит ExoPlayer найти источник ваших media-байтов и отдать их на воспроизведение плееру. Но я не уверен, что найдя этот источник байтов, ExoPlayer не попытается найти file , file descriptor или byte[] которые завернуты (по его мнению) в Ваш InputStream (чтобы попытаться получить random access для перемотки или чтения оконечного moov atom). А так как ничего такого не существует, то он просто откажется воспроизводить ваш поток.

@isabsent
Copy link

isabsent commented May 7, 2018

@AquilesCanta: Is it possible to play media from InputStream if I can't provide an Uri for the method public Uri getUri() of your DataSource interface because the source of my InputStream is a file on a file system inside of encrypted container and such file has no Uri in common sense?

@petersamokhin
Copy link
Author

petersamokhin commented May 7, 2018

@isabsent you can use your own wrapper of ExoPlayer's FileDataSource, and your wrapper can work as proxy — not simple reading, but reading and decryption before providing bytes to the ExoPlayer.


Напишите свой враппер над FileDataSource или каким-то другим более удобным. У меня была схожая проблема — файлы не были зашифрованы, но суть была похожая: просто так взять и передать файл ExoPlayer'у я не мог, нужна была обработка где-то на середине пути.

Все имплементации DataSourceов имеют схожие с InputStream методы, и по сути своей, являются простыми врапперами над ними — имеют методы read, close и так далее.

Вам нужно просто переопределить метод read, и передавать в буффер не сами байты в нужном диапазоне, а байты расшифрованные.

@isabsent
Copy link

isabsent commented May 7, 2018

@petersamokhin: Can you share the code of public int read(byte[] buffer, int offset, int size) and initialization of playback with this InputStreamDataSource?

public class InputStreamDataSource implements DataSource{
    private InputStream is;
    private long fileLength;
    private boolean opened;

    @Override
    public long open(DataSpec dataSpec) throws IOException {
        try {//For simplicity
            is = new FileInputStream(new File(Environment.getExternalStorageDirectory(), "song.mp3"));
            long skipped = is.skip(dataSpec.position);
            if (skipped < dataSpec.position) {
                // assetManager.open() returns an AssetInputStream, whose skip() implementation only skips
                // fewer bytes than requested if the skip is beyond the end of the asset's data.
                throw new EOFException();
            }
            if (dataSpec.length >= 0) {
                fileLength = dataSpec.length;
            } else {
                fileLength = is.available();
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new DataSourceException(1);
        }

        opened = true;
//        if (listener != null) {
//            listener.onTransferStart(this, dataSpec);
//        }
        return fileLength;
    }

    @Override
    public int read(byte[] buffer, int offset, int size) throws IOException {
        //Your implementation?
    }

    @Override
    public Uri getUri() {
        return null;
    }

    @Override
    public void close() throws IOException {
        try {
            if (is != null) {
                is.close();
            }
        } catch (IOException e) {
            throw new DataSourceException(1);
        } finally {
            is = null;
            if (opened) {
                opened = false;
//                if (listener != null) {
//                    listener.onTransferEnd(this);
//                }
            }
        }
    }
}

@petersamokhin
Copy link
Author

@isabsent I don't made InputStreamDataSource and have no implementation of this.

@isabsent
Copy link

isabsent commented May 7, 2018

@petersamokhin:

Вам нужно просто переопределить метод read, и передавать в буффер не сами байты в нужном диапазоне, а байты расшифрованные.

Я понимаю и делал все это для MediaPlayer (Начиная c API 23 он уже принимает InputStream через соответствующую обёртку InputStreamDataSource extends MediaDataSource). Просто хотел по-быстрому воспользоваться вашим кодом чтобы проверить свои подозрения насчет:

я не уверен, что найдя этот источник байтов, ExoPlayer не попытается найти file , file descriptor или byte[] которые завернуты (по его мнению) в Ваш InputStream (чтобы попытаться получить random access для перемотки или чтения оконечного moov atom).

@ojw28
Copy link
Contributor

ojw28 commented May 7, 2018

@isabsent resolved their issue. See #4212.

@google google locked and limited conversation to collaborators Sep 11, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

4 participants