sannies / mp4parser

A Java API to read, write and create MP4 files
Apache License 2.0
2.75k stars 566 forks source link

Question: How to load from InputStream on Android? #357

Open AndroidDeveloperLB opened 5 years ago

AndroidDeveloperLB commented 5 years ago

Is loading from InputStream available?

Currently we have this:

Movie movie = MovieCreator.build(new FileDataSourceViaHeapImpl(filePath));
//We use FileDataSourceViaHeapImpl because it's using less memory and avoids causing OOM on Android

But on Android, sometimes all we have is a Uri and a ContentResolver to create an InputStream from it. We can create the InputStream as much as we wish, and we can have some basic information about the file too (here).

If the answer is that we have one for InputStream, could you please show how to use it, and maybe update the main page of the repository? Which version of the repository should I use?

Both links of those reach to the same URL (here), which is of version 1.1.22 :

image

I don't see any new version, and I don't see alternative currently to just File ... I could implement FileChannel, but I'm not sure what's the best way to do it with what I got, and if it's even possible.

AndroidDeveloperLB commented 5 years ago

OK I've asked about it here:

https://stackoverflow.com/q/54503331/878126

HBiSoft commented 4 years ago

@AndroidDeveloperLB I may have found a possible solution for this, I'm not 100% sure, but it is working on my device. I would like to get your input on this since I do not have a device running Android 10.

FileInputStream inputStream = new FileInputStream(Objects.requireNonNull(mContext.getContentResolver().openFileDescriptor(uri, "r")).getFileDescriptor());
Movie movie = MovieCreator.build(new FileDataSourceImpl(inputStream.getChannel()));
AndroidDeveloperLB commented 4 years ago

You can try on emulator... If you have sample I can try right away, please share it. I don't use this repository anymore.

HBiSoft commented 4 years ago

@AndroidDeveloperLB I will try on emulator (I know emulator is not great with video's), otherwise I will build a new project for you to test, if that is ok?

AndroidDeveloperLB commented 4 years ago

Sure.

marlon-br commented 3 years ago

I made it work on my side with the next approach. That would be great if someone can review the solution:

  1. Implemented RandomAccessSource for uri as that:

    public class RandomAccessSourceFromURIImpl implements RandomAccessSource {
    private ParcelFileDescriptor pfdInput;
    private FileInputStream fis;
    
    public RandomAccessSourceFromURIImpl(Uri treeUri, Context context) {
        try {
            pfdInput = context.getContentResolver().openFileDescriptor(treeUri, "r");
            fis = new FileInputStream(pfdInput.getFileDescriptor());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
    
    @Override
    public ByteBuffer get(long offset, long size) throws IOException {
        try {
            FileChannel fch = fis.getChannel();
            fch.position(offset);
    
            byte[] b = new byte[l2i(size)];
            ByteBuffer buffer = ByteBuffer.wrap(b);
            int bytesRead = fch.read(buffer);
    
            return buffer;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    public void close() throws IOException {
        fis.close();
        pfdInput.close();
    }
    }
  2. Created Movie like that:

FileInputStream inputStream = new FileInputStream(Objects.requireNonNull(getContentResolver().openFileDescriptor(uri, "r")).getFileDescriptor());
RandomAccessSourceFromURIImpl randomAccessSourceFromURIImpl = new RandomAccessSourceFromURIImpl(uri, this);
Movie m = MovieCreator.build(inputStream.getChannel(), randomAccessSourceFromURIImpl, "inmem");

It seems to work on Android 10 and I do not see any hacks in this code, so suppose that could be the solution