sannies / mp4parser

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

How do I modify a video with MP4Parser using its URI (the one based on the MediaStore)? #395

Open Gensoukyou1337 opened 4 years ago

Gensoukyou1337 commented 4 years ago

Right now I'm using MP4Parser to trim videos for further editing. It's worked just fine, but it fails in Android Q. When I just provide the path to the video, the error stacktrace says, "EACCES (Permission Denied)".

Apparently Android Q no longer allows direct access to files even with the READ_ACCESS_STORAGE permission, so I now need some way to access the files using their MediaStore URI. The best I can do is open an InputStream via the ContentResolver, but I don't know which object to put it into.

Basically, how do I generate Movies using MediaStore URIs?

HBiSoft commented 4 years ago

I deleted my previous comment because it doesn't seem like the link I mentioned resolved the issue.

Google is in the process of forcing Android developers to use only content uri's instead of file uri's. It has been coming for some time now.

The only way Android developers will be able to use this library going forward (Android 10>) is to copy the selected file to your application's directory. By doing this, you will be able to get the file:// Uri and pass that to the Movie object. The problem with this is that it will negatively affect the user experience because the user will have to wait while the file is being copied and this can take quite some time depending on the file size.

It would be great if @sannies could implement the option to provide an InputStream to the Movie object.

I would suggest you change the title of the question to something like "Add option to pass InputStream to Movie". Also, this question has been asked before here #357

ghost commented 4 years ago

I hope author will support this. I removed a feature when my app upgraded to Android 10.

HBiSoft commented 4 years ago

Using an older version of mp4parser I'm able to pass the following:

FileInputStream inputStream = new FileInputStream(context.getContentResolver().openFileDescriptor(uri, "r").getFileDescriptor());
video = MovieCreator.build(new FileDataSourceImpl(inputStream.getChannel()));

For some reason this was removed and file path was prefered.

It works perfectly on Android 10<, but some files do not work because there have been improvements made to the project since that release.

The old version of mp4parser did not have the following: https://github.com/sannies/mp4parser/blob/d3c68436f0507a23a740f262cf3259557ea9ce93/muxer/src/main/java/org/mp4parser/muxer/container/mp4/MovieCreator.java#L63

I assume that is why I'm getting the following error on some files:

Attempt to invoke virtual method 'long[] com.coremedia.iso.boxes.ChunkOffsetBox.getChunkOffsets()' on a null object reference

I tried making the necessary change, but I was not able to build the project because the following is not supported by android:

https://github.com/sannies/mp4parser/blob/d3c68436f0507a23a740f262cf3259557ea9ce93/muxer/src/main/java/org/mp4parser/muxer/tracks/mjpeg/OneJpegPerIframe.java#L13

So, I will be able to implement the changes necessary, if I'm able to build the project...