tanersener / mobile-ffmpeg

FFmpeg for Android, iOS and tvOS. Not maintained anymore. Superseded by FFmpegKit.
https://tanersener.github.io/mobile-ffmpeg
GNU General Public License v3.0
3.85k stars 786 forks source link

Android: SAF & FileDescriptor #334

Closed PaulWoitaschek closed 4 years ago

PaulWoitaschek commented 4 years ago

I need to use this library on android using an uri from SAF. Therefore it would be great if you implemented an api for using a file descriptor.

An example for how to implement this so the uir can be passed to the NDK can be found here: https://github.com/wseemann/FFmpegMediaMetadataRetriever/blob/b42986fb4044c54131379407598d8ac0ff1a3326/gradle/fmmr-library/core/src/main/java/wseemann/media/FFmpegMediaMetadataRetriever.java#L214

tanersener commented 4 years ago

Can you please give some more info like what is the issue you're facing right now and why that feature needs to be implemented in the library rather than the application?

PaulWoitaschek commented 4 years ago

I need to parse metadata of a lot of media files from the users phone storage.

On Android 10 you don't have access to the users sd card using the file api: https://developer.android.com/about/versions/10/privacy/changes#scoped-storage

Instead you need to use the SAF framework: https://developer.android.com/guide/topics/providers/document-provider

You fire an intent: https://developer.android.com/reference/android/content/Intent.html#ACTION_OPEN_DOCUMENT

And get an uri in onActivityResult. This uri is no file uri but a content provider uri. Therefore you can't use it with mobile-ffmpeg at all (unless you make a deep temporary copy of the file, which is no option here as I can't duplicate gigabytes of media.)

You can use the content provider to obtain a file descriptor: contentResolver.openFileDescriptor(uri, "r"). and work with that. But this need integration with mobile-ffmpeg.

tanersener commented 4 years ago

Thanks for explaining the issue in detail.

MobileFFmpeg for Android is made of two modules; one native module (written in C/C++) and one Java module. There is a JNI layer between these two and Java module sends API requests to native module through this JNI layer.

Argument parsing and opening input/output files are all implemented in native module. Supported protocols are also defined there. As far as I know, SAF is not available in NDK. That means that I can't use SAF inside the native module. So, I don't think that SAF can be integrated with MobileFFmpeg. Do you have any recommendations?

PaulWoitaschek commented 4 years ago

@wseemann

Can you help out here?

HBiSoft commented 4 years ago

@tanersener I'm not that familiar with NDK and I do not want to highjack this issue, I just thought I would give my 2 cents.

As @PaulWoitaschek mentioned, on Android we can not access the file (or its path) directly, unless the file is located in our application's directory. Instead, we have to make use of the ContentResolver to open a FileDescriptor. As shown below:

FileDescriptor fd = getContentResolver().openFileDescriptor(Uri, "r").getFileDescriptor();

In the project that was provided as an example above, the owner of that library checks to see if the Uri that was passed is a content:// Uri. If it was then he uses a FileDescriptor instead of passing the path of the file, please have a look here:

https://github.com/wseemann/FFmpegMediaMetadataRetriever/blob/b42986fb4044c54131379407598d8ac0ff1a3326/gradle/fmmr-library/core/src/main/java/wseemann/media/FFmpegMediaMetadataRetriever.java#L214


So you can create 2 native methods, one for handling file paths(as you have it currently): https://github.com/tanersener/mobile-ffmpeg/blob/917c22e20947e89d4c1cf4ce4290909360f8973b/android/app/src/main/java/com/arthenica/mobileffmpeg/Config.java#L642

and one for passing the FileDescriptor, something like this:

native static int nativeFFmpegExecute((final String[] arguments, final FileDescriptor fd) {

On the C/C++ side you can then handle this depending on which one of the above was called. Of course, there will also have to be another method added in FFmpeg.java:

https://github.com/tanersener/mobile-ffmpeg/blob/917c22e20947e89d4c1cf4ce4290909360f8973b/android/app/src/main/java/com/arthenica/mobileffmpeg/FFmpeg.java#L55

Like this:

public static int execute(final String[] arguments, final FileDescriptor fd) {

Developers using your library could then have the option to pass a FileDescriptor, something like this:

FileDescriptor fd = getContentResolver().openFileDescriptor(Uri, "r").getFileDescriptor();
//Note that, instead of passing the path at the end, FileDiscriptor is passed instead.
FFmpeg.execute("some_commands_by_developer"+outputPath, fd);

Edit:

This is how he handles it from C:

https://github.com/wseemann/FFmpegMediaMetadataRetriever/blob/b42986fb4044c54131379407598d8ac0ff1a3326/gradle/fmmr-library/library/src/main/jni/metadata/ffmpeg_mediametadataretriever.c#L304

int set_data_source_fd(State **ps, int fd, int64_t offset, int64_t length) {
    char path[256] = "";

    State *state = *ps;

    ANativeWindow *native_window = NULL;

    if (state && state->native_window) {
        native_window = state->native_window;
    }

    init(&state);

    state->native_window = native_window;

    int myfd = dup(fd);

    char str[20];
    sprintf(str, "pipe:%d", myfd);
    strcat(path, str);

    state->fd = myfd;
    state->offset = offset;

    *ps = state;

    return set_data_source_l(ps, path);
}
alexcohn commented 4 years ago

There is no need to change the C++ side at all. A neat trick lets you work with a file path instead of the FileDescriptor. It's based on the specs of the Linux /proc/self/fd files.

As service to the community, the integer descriptor may be extracted on the Java side of the library (if it sniffs the content:// prefix), but may be easily done by the app developer who uses the library.

kingvhit commented 4 years ago

Hi, another reason that must support FileDescriptor is defined here https://github.com/tanersener/mobile-ffmpeg/issues/185

Above trick, I am testing with the other project with same purpose, but this behaviour can be changed by Google in the future.

tanersener commented 4 years ago

I know you expect the library to handle URIs internally but I think using the following method is the most elegant solution for SAF.

File descriptors received from SAF can be used using the pipe protocol. Both input and output files can be defined with pipe protocol. But some file formats require the output to be seekable, so pipe protocol will fail with them. Be careful about them.

String safUriToFFmpegPath(final Uri uri) {
    try {
        ParcelFileDescriptor parcelFileDescriptor = getContentResolver().openFileDescriptor(uri, "r");
        return String.format(Locale.getDefault(), "pipe:%d", parcelFileDescriptor.getFd());
    } catch (FileNotFoundException e) {
        return "";
    }
}
RowlandOti commented 4 years ago

All this is unnecessary, I pondered upon this myself and hated this elegant library for it. I did it using a utility function like:

val filePath = RealPathUtil.getRealPath(
                           context,
                            currentUri
                        )

so, contentUri to filePath is what you need. It is just as fast.

HBiSoft commented 4 years ago

@RowlandOti The RealPathUtil you are referring to is probably querying the _data column to get the path of the file. I have released a library myself that converts a Uri to a "real" path. The problem is that the _data column can no longer be accessed when you are targeting 29.

RowlandOti commented 4 years ago

You are right, this will only work for API < 29. This was the only caveat. @HBiSoft

HBiSoft commented 4 years ago

@tanersener I've tested the pipe protocol and it is working.

But some file formats require the output to be seekable

Can you please explain what is meant with the above?

tanersener commented 4 years ago

@HBiSoft

Muxers of some file formats like mp4 and mov requires the output to be seekable to write file metadata/header information correctly. Unfortunately pipe protocol does not support seeking. Therefore you may receive muxer does not support non seekable output error if you try to use pipe protocol in an output file.

There are some options that can be used to overcome this limitation, like -movflags frag_keyframe or -movflags empty_moov. But using these options has consequences. For example, you may not have a seekable video file at the end. So, you need to be careful about the options you use. FFmpeg's mov, mp4, ismv guide includes the list of options and explains what they are used for. It may help you to understand the those consequences better.

Update: Unfortunately input files are affected from this limitation too. You can't use mp4 and mov files with pipe protocol as input unless they are created using -movflags +faststart. There is not way to overcome this limitation.

HBiSoft commented 4 years ago

@tanersener Thank you for your informative reply. As I understand it, this will only be an issue if I use the pipe protocol with the output and not when I use it with the input? If this is the case, I will then be able to set the output path to my application directory and all will be good.

kingvhit commented 4 years ago

There is no need to change the C++ side at all. A neat trick lets you work with a file path instead of the FileDescriptor. It's based on the specs of the Linux /proc/self/fd files.

As service to the community, the integer descriptor may be extracted on the Java side of the library (if it sniffs the content:// prefix), but may be easily done by the app developer who uses the library.

About this solution?, why does not any one interest this one?

tanersener commented 4 years ago

@HBiSoft I missed some details about input files. Updated my previous post with the following information. It looks like safUriToFFmpegPath can be used as a temporary workaround but a protocol like saf: or fd: has to be implemented.

Unfortunately input files are affected from this limitation too. You can't use mp4 and mov files with pipe protocol as input unless they are created using -movflags +faststart. There is not way to overcome this limitation.

@kingvhit That solution is a trick that works for some devices and doesn't work on some others. I tested it and it didn't work for me. I receive Permission denied errors when I try. You can try and see if it works for you.

kingvhit commented 4 years ago

@tanersener : Hi, I have tested on Xiaomi Mi 8 Pro (Adroid 9), and Google Pixel XL 3 (android 10) and all of them working well.

I have concern when you told that it's is not really work for all devices :'(. Could you please tell me which device are you testing on before.

Just I want to re-check it on my app.

HBiSoft commented 4 years ago

@tanersener I agree with:

a protocol like saf: or fd: has to be implemented.

I think the best is to use fd: because we can open a FileDescriptor with any(almost) Uri. Then we, using the library, can pass the FileDescriptor instead of the path. This will work on all API's and no "hacks" are involved. I know my first comment means more work, but I believe it is the best/correct way - https://developer.android.com/training/data-storage/shared/media#native

tanersener commented 4 years ago

@kingvhit My old Galaxy A5 (2016) (Android 7.0) receives /proc/self/fd/66: Permission denied. Also Pixel 2 Simulator with API 24 also receives permission denied error for me.

alexcohn commented 4 years ago

@tanersener I am afraid this only means that there is no universal way of handling this. I didn't expect Permission denied on Android 7, but anyways you only need this workaround for API 29 and higher. BTW, my Android 7.0 device handles this perfectly. I only bothered to handle input in my simple exercise, but it works even cross-process: see https://github.com/alexcohn/FFmpeg-Android/commit/686c4b50653e39c5acb181b0d09cec03e873af5d

tanersener commented 4 years ago

@alexcohn Tried to test your pull request to see whether I'm missing something but I still receive /proc/11193/fd/52: Permission denied on my device. Attached the logs here if you want to take a look.

alexcohn commented 4 years ago

Which file did you choose? For me, uri content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fqq.mov points to /sdcard/Download/qq.mov (a.k.a. /storage/emulated/0/Download/qq.mov).

HBiSoft commented 4 years ago

I tested with a file on my SD Card, the content uri is content://com.android.externalstorage.documents/document/6330-6333%3ATest.mp4. It is pointing to /storage/6330-6333/Test.mp4 and I also get permissions denied - /proc/23074/fd/70: Permission denied

I tested the above by calling:

protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        if (requestCode == SELECT_VIDEO_REQUEST && resultCode == RESULT_OK) {
                ParcelFileDescriptor parcelFileDescriptor = null;
                try {
                    parcelFileDescriptor = getContentResolver().openFileDescriptor(data.getData(), "r");
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
                int fd = parcelFileDescriptor.getFd();
                int pid = Process.myPid();
                String mediaFile = "/proc/" + pid + "/fd/" + fd;

                int rc = FFmpeg.execute("-i "+mediaFile+" -crf 18 -c:v libx264 -c:a copy "+outputPath");
                if (rc == RETURN_CODE_SUCCESS) {
                    Log.i(Config.TAG, "Command execution completed successfully.");
                } else if (rc == RETURN_CODE_CANCEL) {
                    Log.i(Config.TAG, "Command execution cancelled by user.");
                } else {
                    Log.i(Config.TAG, String.format("Command execution failed with rc=%d and the output below.", rc));
                    Config.printLastCommandOutput(Log.INFO);
                }
        }
    }
RowlandOti commented 4 years ago

By default, by experimentation, I noticed that drives mounted to /storage/XXXX-XXX will by default have write permissions denied.

I don't think we should face similar problems with /sdcard/Download/ aka /storage/emulated/0/Download/ as both have read/write access.

tanersener commented 4 years ago

@alexcohn

If I select /storage/emulated/0/Download/video1.mp4 file, it gets content://com.android.externalstorage.documents/document/primary%3ADownload%2Fvideo1.mp4 uri. I don't know why it has a different format then yours or from @HBiSoft's file.


opened content://com.android.externalstorage.documents/document/primary%3ADownload%2Fvideo1.mp4 as /proc/14517/fd/52
/proc/14517/fd/52: Permission denied
HBiSoft commented 4 years ago

@tanersener The reason why it is different is - If you select a file from the downloads provider directly, it will return the Uri as content://com.android.providers.downloads.documents/document/3656 or like in @alexcohn's case content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fqq.mov and if you select a file by going to your internal storage then Downloads, it will return content://com.android.externalstorage.documents/document/primary%3ADownload%2FNameOfVideo.mp4.

See the deffirence between com.android.providers.downloads and com.android.externalstorage.documents/document/primary.


@alexcohn If the Uri returned is a raw file then it works. For example, if I select a file from the downloads provider and I get a Uri like

content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fqq.mov

then it works, but if I select the same file, by selecting it from Internal Storage/Download and the returned Uri is

content://com.android.externalstorage.documents/document/primary%3ADownload%2F`Fqq.mov

then I get the permissions denied.

tanersener commented 4 years ago

@HBiSoft Thanks for explaining that. Unfortunately, selecting a file from one of the providers doesn't improve the case for me. Selected a file from Videos provider which was actually under the /storage/emulated/0/Pictures/ path and got the url content://com.android.providers.media.documents/document/video%3A727, which still receives permission denied errors.

HBiSoft commented 4 years ago

@tanersener I see. I also tested with different providers/paths and it was very inconsistent, some worked and some didn't. The same when using the pipe protocol, a lot of videos failed, especially videos that were recorded with an iPhone. What other options do we have? How is it that it works with the FFmpegMediaMetadataRetriever library as mentioned here?

tanersener commented 4 years ago

I don't know any other options we can try right now.

I think FFmpegMediaMetadataRetriever is using an offset to skip the data and just reads the metadata/header. But I'm not sure, I think @alexcohn may have a better idea.

alexcohn commented 4 years ago

Unfortunately, I don't know how this can be overcome. Regarding the FFmpegMediaMetadataRetriever, they use ffmpeg as library, so they are not limited with filenames-based API. Having an open descriptor, you can access the file the way you want (e.g. funopen()).

alexcohn commented 4 years ago

People think that the problem loading media files (and some other types) from /sdcard is a bug: https://issuetracker.google.com/issues/147619577. More stars there may have a positive effect! I gave mine.

pawaom commented 4 years ago

can this help(I am a novice, hope this works)

https://www.youtube.com/watch?v=oIn0MZQJpp0&feature=youtu.be&t=961

https://stackoverflow.com/questions/43815688/passing-a-native-fd-int-to-ffmpeg-from-openable-uri

https://proandroiddev.com/a-story-about-ffmpeg-in-android-part-ii-integration-55fb217251f0

https://github.com/Javernaut/WhatTheCodec

is android.system.os.lseek useful in anyway

pawaom commented 4 years ago

@kingvhit My old Galaxy A5 (2016) (Android 7.0) receives /proc/self/fd/66: Permission denied. Also Pixel 2 Simulator with API 24 also receives permission denied error for me.

according to this video , there were recent changes in android , to support android.system.os.lseek so may be /proc/self/fd/66 was not supported earlier

https://www.youtube.com/watch?v=oIn0MZQJpp0&feature=youtu.be&t=961

as per this , it looks like to be the expected behavior

https://developer.android.com/training/data-storage/shared/media#native

so we can use

Uri contentUri = ContentUris.withAppendedId(
        MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
        cursor.getLong(Integer.parseInt(BaseColumns._ID)));
String fileOpenMode = "r";
ParcelFileDescriptor parcelFd =
        resolver.openFileDescriptor(contentUri, fileOpenMode);
if (parcelFd != null) {
    int fd = parcelFd.detachFd();
    // Pass the integer value "fd" into your native code. Remember to call
    // close(2) on the file descriptor when you're done using it.
}

to manage it in a better way we may check the android version using

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
//  use /proc/self/fd/66
}
else {
// use file path
}

I dont know if this is the perfect solution, but till we find a better sollution we can use this, as I said earlier I am a Novice, to FFmpecg and android can some one help with the way to get '/proc/self/fd/66' I think we can get it from a native code (I dont know NDK) can some body share a .so file to pass it to the FFmpeg code

thanks

alexcohn commented 4 years ago

You don't need to check SDK_INT. The detached file descriptor will work for earlier Android versions, just as well. The caveat is that on Q, you cannot use /proc/self/fd/66 if it points to a file on sdcard (/sdcard/Downloads are still OK, but, as far as I understand, through a different Provider).

HBiSoft commented 4 years ago

@alexcohn I agree. It is clear that the only way is to pass an open file descriptor. Is there any reason this will not work?


Edit: This seems like exactly what we want (I see you commented on it):

https://stackoverflow.com/a/59004193/8199772

pawaom commented 4 years ago

I have asked for help here 6963

I dont know if they would help, but if somebody can really clarify on this accessing files in native C/C++ code with Google Scoped Storage API thing, it would be really helpful, otherwise many apps which are in production may stop working

pawaom commented 4 years ago

You don't need to check SDK_INT. The detached file descriptor will work for earlier Android versions, just as well. The caveat is that on Q, you cannot use /proc/self/fd/66 if it points to a file on sdcard (/sdcard/Downloads are still OK, but, as far as I understand, through a different Provider).

just a thought, how are you getting the fd int,

I guess, one should use

String fileOpenMode = "r";
ParcelFileDescriptor parcelFd =
        resolver.openFileDescriptor(contentUri, fileOpenMode);

where String fileOpenMode = "r"; is the important part

kingvhit commented 4 years ago

You don't need to check SDK_INT. The detached file descriptor will work for earlier Android versions, just as well. The caveat is that on Q, you cannot use /proc/self/fd/66 if it points to a file on sdcard (/sdcard/Downloads are still OK, but, as far as I understand, through a different Provider).

just a thought, how are you getting the fd int,

I guess, one should use

String fileOpenMode = "r";
ParcelFileDescriptor parcelFd =
        resolver.openFileDescriptor(contentUri, fileOpenMode);

where String fileOpenMode = "r"; is the important part

you can easily get the fd number by method

String fileOpenMode = "r";
ParcelFileDescriptor parcelFd =
        resolver.openFileDescriptor(contentUri, fileOpenMode);
parcelFd.getFdId();

I don't know why, but could you please write down all your expected result of your issue

pawaom commented 4 years ago

@kingvhit My old Galaxy A5 (2016) (Android 7.0) receives /proc/self/fd/66: Permission denied. Also Pixel 2 Simulator with API 24 also receives permission denied error for me.

unfortunately my Android Q emulator has crashed, and not starting at all, while I was testing, so it will take time , the problem is not about getting fd but may be the permission required to read the file, which we can access using String fileOpenMode = "r";

kingvhit commented 4 years ago

@kingvhit My old Galaxy A5 (2016) (Android 7.0) receives /proc/self/fd/66: Permission denied. Also Pixel 2 Simulator with API 24 also receives permission denied error for me.

unfortunately my Android Q emulator has crashed, and not starting at all, while I was testing, so it will take time , the problem is not about getting fd but may be the permission required to read the file, which we can access using String fileOpenMode = "r";

Let me know, which is expected result you want to do.

E.g:

I have to make my app working with all of above case, with some tip trick in this issue. If you understand what is my question, let me more detail of you case.

pawaom commented 4 years ago

case 1 I want to input a file from A (uri, file) and then process -> export the file results to B destination (uri, file)

kingvhit commented 4 years ago

Firstly, as you target SDK to 29, when you pick a file from the Other Apps (Google Driver, File Manager...) you just get a uri with content:// prefix.

My solution is:

First, check a uri is internal storage or Document Provider by other app (Google Driver, One Driver, ...) or is a external storage (sd-card)

NOTE: We only have permission to access internal storage by absolute path, like /storage/emulated/0/DCIM... and we don't have any permission (read/write) to access to the other absolute path of the other Document Provider or private internal storage of other app like /storage/emulated/0/data/data/com.googledrive.com/** except owner of that apps.

Bellow is a tip trick of above issue:

Bellow is a way to copy file from all of URI into cached dir without permission

val contentResolver = getApplication<Application>().contentResolver
val inputStream = contentResolver.openInputStream(uri)
val outputStream = FileOutputStream(getApplication<Application>().cacheDir)

Read file by absolute file path above to continue working aboslute path (input file) on your app.

// write file into target uri inputStream.copyTo(out)

HBiSoft commented 4 years ago

@kingvhit I do not believe this is a feasible solution.

Let's say the file size if 2GB>, it will take very long to copy/write a new file. By doing it as you say, you will have to write the file to your applications directory to get a file scheme Uri and get the path from that Uri(the user will have to wait for the file to be copied/written), then run the FFmpeg command (the user will have to wait again).

If the file is from (Google Driver, One Drive, ...) then there is no other way then to copy the file to your application's directory and get the path from that. But I do not believe that this should be the option with SD Card.

Also, with what you said:

First, check a uri is internal storage or Document Provider by other app (Google Driver, One Driver, ...) or is a external storage (sd-card)

AFAIK, there is no way to check if a Uri points to a file on the SD Card. Look here


I feel this should be handled by the library and I think we should stop looking at "workarounds/tricks" and focus on doing it right.

As I mentioned in my previous comment, this answer got it working.

In this question (above), he mentioned the following (he is talking about /proc/self/fd/" + fd):

Passing this to native C/C++ code works, but only if the file is in phone main storage. If the user tries to open a file that is on external SD card inserted into the phone slot, it does not work - there is no read permission for the file opened this way. I can only grab the file descriptor int number and use fdopen(fd). But this will require modifying the source code of 3rd party libraries (open source or licensed), and a big headache, whenever the original source of these libraries is updated.

And with the solution he provided, there is no need to change the native library itself.

After wasting another good day of my life on the Android "Scoped Storage" B.S., I found a solution that works, without modifying the source of 3rd party native libraries, provided that one has the source of these libraries and can build them.

kingvhit commented 4 years ago

@HBiSoft : I agree with you about this is a tip/tricks to handle this issue. May I discuss in wrong topic, because my app does not have any solution to modify native code, but FFmpeg mobile here can do it.

This is a last confirm that I was tested on my app.

If the file is from (Google Driver, One Drive, ...) then there is no other way then to copy the file to your application's directory and get the path from that. But I do not believe that this should be the option with SD Card.

=> We don't need to care about this folder is a member of Document Provider or SD-card, but we can check writable permission with its file. All of them is the same. If write permission is no, use content resolver to open uri as input stream from this file from them, then write to application dir.

I agree with you, it's not best solution to handle the large file but this case is only appear when user picking file or input file, output file which are not internal storage where our app have full permission to read/write dirrectly (just only need READ/WRITE permission). If the input file, output file still internal storage, we can still using fd path based proc (/proc/self/fd/66).

pawaom commented 4 years ago

I tested with a file on my SD Card, the content uri is content://com.android.externalstorage.documents/document/6330-6333%3ATest.mp4. It is pointing to /storage/6330-6333/Test.mp4 and I also get permissions denied - /proc/23074/fd/70: Permission denied

I tested the above by calling:

protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        if (requestCode == SELECT_VIDEO_REQUEST && resultCode == RESULT_OK) {
                ParcelFileDescriptor parcelFileDescriptor = null;
                try {
                    parcelFileDescriptor = getContentResolver().openFileDescriptor(data.getData(), "r");
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
                int fd = parcelFileDescriptor.getFd();
                int pid = Process.myPid();
                String mediaFile = "/proc/" + pid + "/fd/" + fd;

                int rc = FFmpeg.execute("-i "+mediaFile+" -crf 18 -c:v libx264 -c:a copy "+outputPath");
                if (rc == RETURN_CODE_SUCCESS) {
                    Log.i(Config.TAG, "Command execution completed successfully.");
                } else if (rc == RETURN_CODE_CANCEL) {
                    Log.i(Config.TAG, "Command execution cancelled by user.");
                } else {
                    Log.i(Config.TAG, String.format("Command execution failed with rc=%d and the output below.", rc));
                    Config.printLastCommandOutput(Log.INFO);
                }
        }
    }

how do you create file in outputPath can you please elaborate

HBiSoft commented 4 years ago

@pawaom outputPath is my applications directory.

File directoryToStore = getBaseContext().getExternalFilesDir("tempDirectory");
if(directoryToStore != null) {
    if (!directoryToStore.exists()) {
        if (directoryToStore.mkdir()) ; //directory is created;
    }
}
// Output path passed to FFmpeg
String outputPath = directoryToStore+"/testFile.mp4";

The path will be:

/storage/emulated/0/Android/data/com.package.name/files/tempDirectory/testFile.mp4
pawaom commented 4 years ago

any update guys , has anyone tested on multiple devices using the Firebase Test lab,

https://www.youtube.com/watch?v=o0aUuKztO4A

I tested with a file on my SD Card, the content uri is content://com.android.externalstorage.documents/document/6330-6333%3ATest.mp4. It is pointing to /storage/6330-6333/Test.mp4 and I also get permissions denied - /proc/23074/fd/70: Permission denied

have you used takePersistableUriPermission

if (resultCode == RESULT_OK) {
                getContentResolver().takePersistableUriPermission(data.getData(),
                        Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            } 
HBiSoft commented 4 years ago

@pawaom

has anyone tested on multiple devices using the Firebase Test lab

What do you want to test? There is nothing to test at the moment.

have you used takePersistableUriPermission

Yes, I did.


@tanersener Can you have a look at this(and the answer)? It looks like we can add that to the build and perhaps create a native method, similar to nativeFFmpegExecute and return the path, or just use that file.

tanersener commented 4 years ago

@HBiSoft Solution posted in the answer has to be tested. I don't know what will that idiocy_fopen_fd function return for files on the cloud?

pawaom commented 4 years ago

so what is this all about

1) file path access to (read) media will be allowed 2) media modification API (To edit delete)

https://youtu.be/UnJ3amzJM94?t=1451

so what are we supposed to do , its really confusing now