Search code examples
androidlinuxffmpegjava-native-interface

FFmpeg and file descriptors in Android Lollipop


I'm going to use FFmpeg in an Android project as a JNI library and I know about the limitations of Kitkat. Since with the new release of Lollipop there is the possibility for third-party apps to access to external microsd I would like to exploit it. I've read this useful question so I use a ACTION_OPEN_DOCUMENT_TREE intent, the user chooses a folder and than I use a similar code to get a file descriptor. Then I send this UNIX file descriptor to a jni function. I've created a demo, if I use something like this:

int descriptor = a_file_descriptor;
FILE* fp = fdopen(descriptor , "w");
fprintf(fp, "Hello from Lollipop!");
fclose(fp);

everything is fine. The problem is that I would like to extract the complete file name from the file descriptor. It's possible with some tricks available for Linux but if I do an fopen and try to fprintf something in the file nothing happens. So I imagine I should use the file descriptor, but how to use it with FFmpeg? I read about the pipe option but it seems for command line only. Thanks in advance for the help.


Solution

  • The problem is that I would like to extract the complete file name from the file descriptor.

    Yes, it's possible to extract the full path of a file from file descriptor with a little trick on Linux. Every created process has a directory under /proc/[pid], you can find the resources about a process under the process directory /proc/[pid] including the open file descriptors. Then opened file descriptor exist as a form of /proc/[pid]/fd/[fd_number], e.g /proc/17059/fd/20. This is usually a symbolic link to the real file path, so we can get the full path by resolving the symbolic link.

    The following is the demonstration code run on Linux. Yes, it will work from your JNI call on Android.

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <limits.h>
    #include <stdlib.h>
    
    int main(int argc, char **argv) {
    
        int fd;
        char path[512] = { 0 };
        char* real_path = NULL;
    
        if ((fd = open("/tmp/test", O_CREAT | O_WRONLY)) == -1) {
            fprintf(stderr, "open fail");
        }
    
        sprintf(path, "/proc/%d/fd/%d", getpid(), fd);
    
        if (path[0] != '\0') {
            printf("fd path is %s\n", path);
            real_path = realpath(path, NULL);
            if (real_path != NULL) {
                printf("get full path from fd %s\n", real_path);
                free(real_path);
            }
        }
    
        exit(EXIT_SUCCESS);
    }