How to Port ffmpeg (the Program) to Android–Ideas and Thoughts

Why ffmpeg for Android and The App

I was working on a project that requires transcoding of video files and then play these files on Android device. The definite tool to do this is ffmpeg. I can do it on Desktop and transfer the files to Android, but why not just transcode on Android itself?

Then I searched for ffmpeg and transcoding tools on Android, but cannot find any. And since I’ve built ffmpeg libraries for Android before, I believe it is also doable to port the ffmpeg command line utility to Android. So I started doing it.

Below is the screen capture of the Android app (I released it as ffmpeg for Android Beta),

devicedevice1

Figure 1. Screenshots of ffmpeg for Android

Currently it only supports armv7 processor, the one that my Nexus One device uses.

How did I Port it?

The main design goal is to change as few lines of code as possible for ffmpeg.c file. To meet this goal, I decoupled the UI and ffmpeg processing into two processes.

Running ffmpeg on a separate processes has a few advantages,

  • ffmpeg uses a lot of exit function, which will terminate the process. Use a separate process for ffmpeg will ensure the termination of ffmpeg won’t affect the front UI.
  • ffmpeg is processing intensive, running it on a separate process will not affect the responsiveness of front UI.

There’s inter-process communication problem to solve (IPC) so the two processes can communicate with each other. The UI will be able to start and stop ffmpeg, and ffmpeg will send output message to UI.

From UI to ffmpeg is simple, I implement a service that will call ffmpeg. And we start the service using Intent. It’s the same for stop command.

From ffmpeg to UI, there’re a few choices. pipe, socket, etc. But since it requires only a very simple one way communication channel (ffmpeg write, UI read), I just use text files. ffmpeg dump all outputs to text files, and UI read it every second or two (you can also use file observer and update the UI only when the text files changes).

What are the Changes for ffmpeg.c

With the design above, the change for ffmpeg.c is simple.

  • Change the main(int argc, char **argv) function prototype to a java JNI interface prototype that Android java code can call.
  • Change the output to stdout to the text files we created.
  • Comment out a few lines that cause the compilation error.

A little More Thoughts

I’m thinking this method can be used to port lots of other applications to Android too. Two processes, running the background processing utility as a service, change the main method to an native interface so Java code can call, use intents and text files for communication, etc.

If you would like to try out this app, go to https://market.android.com/developer?pub=roman10. Note that it’s for armv7 processor only.

0 thoughts on “How to Port ffmpeg (the Program) to Android–Ideas and Thoughts”

  1. Hi Roman,

    Your article is very interesting. I have follow this article for writing an android demo application that can call ffmpeg by command line.

    I have change ffmpeg.c with the main(int argc, char **argv) function prototype to a java JNI interface prototype that Android java code can call.

    But my android app cannot call this native function, it said this function is not implemented.

    I also read you article here http://www.roman10.net/?p=389 and thought that I should change build_android.sh or configure files but it doesn’t work.
    Would you please give me any suggestion for me to call my native function from android?

    Thanks in advance and best regards.


    Nguyen An Bien

  2. Hi Roman,

    I had called my native function successfully, I’ve just added cmdutils.c to LOCAL_SRC_FILES in Android.mk file.

    Now there is new problem that when my native function run to parse_options function, it cannot pass this function, there is some errors when run to this, have you met this problem ever? Please give me some suggestion if you have any idea.

    Thanks in advance and best regards.


    Nguyen An Bien

      1. Hi Roman,

        Thanks for your reply.

        I’ve known how to pass the parameter type from Java to native code, from Android I pass jstring cmd to native code, it understand my cmd (e.g: cmd = “ffmpeg -f image2 -i /mnt/sdcard/Books/1.jpeg /mnt/sdcard/Books/test.mp4
        “), I also print log to ensure my function is correct and parse cmd to char **argv and int argc, everything work correctly.
        My problem now is that when my function call parse_option function from cmdutils.c, it cannot parse options like -f, -i, it always exit program here.

        Please give me some suggestion if you have any idea.

        Thanks and best regards.


        Nguyen An Bien

  3. Hi,
    Congratulations for your application and the thanks for your great articles…

    I have a question : why did you only provide a Armv7 version ?
    Can’t you provide other lib versions, and so other application versions ?

    Thanks

    1. Thank you!
      My phone is Armv7, I don’t have other phones to test, so…
      If I have time to improve on this app, I’ll make it available on all CPUs and probably provide a convenient to use GUI. Current UI is just for demo.

  4. Hi Roman, interesting. But in fact the build_android.sh script that you showed in a previous post does create an ffmpeg binary.

    I tryied to use it by copying it to /system/bin (with root access and rw permissions of course) and just ran a adb shell and tryied to execute from there. It didn’t seem to work either, as I get a segmentation fault.

    Am I going the wrong way here? I don’t care about updating the ui, I just want to run the executable in background.

    1. The ffmpeg compiled using build_android.sh can only be used using command line and with super user privilege. While the method mentioned in this article allows you to create an app with ffmpeg as the engine running at background. And it doesn’t require super user privilege.

      1. Thanks for the quick response. I just wanted to ask the earlier build script u mentioned for porting ffmpeg, will it work for transcoding or should we make some changes to build_android.sh build script.

        1. The build is for building the ffmpeg library. You don’t need to change the build script, but you’ll need to change part of ffmpeg.c code.

          1. Thanks Roman. This is the only android tutorial that worked for me. I will share this with my friends. Thanks a million. 🙂

          2. Hi roman10:

            I try “nm -D libffmpeg.so” to dump all function names. The main() in ffmpeg.c is not compiled into libffmpeg.so. Do I have to modify your build_android.sh build script?

            Bob

        2. Hi pranav, can you share this working project (ffmpeg beta)……as i am getting some errors in compilation….

          urgently required….(nnnaaavvv@gmail.com)

  5. Hi Roman,

    I’ve built ffmpeg library thanks to your posts, but I’m not able to do the changes to ffmpeg.c part. Could you explain a little more about how to dump outputs to text files and change the stdout?.

    Thanks a lot.

    Álvaro

  6. Hey Roman
    I change ffmpeg.c but i didn’t understand that what do you mean about : 2- Change the output to stdout to the text files we created.

    Here is my code , is it true?

    JNIEXPORT jint JNICALL Java_com_parsapp_actionmovie_MainActivity_main(JNIEnv *pEnv, int argc, char **argv) {
    int64_t ti;

    av_log_set_flags(AV_LOG_SKIP_REPEATED);

    if(argc>1 && !strcmp(argv[1], "-d")){
    run_as_daemon=1;
    verbose=-1;
    av_log_set_callback(log_callback_null);
    argc--;
    argv++;

    }

    avcodec_register_all();
    #if CONFIG_AVDEVICE
    avdevice_register_all();
    #endif
    #if CONFIG_AVFILTER
    avfilter_register_all();
    #endif
    av_register_all();

    #if HAVE_ISATTY
    if(isatty(STDIN_FILENO))
    avio_set_interrupt_cb(decode_interrupt_cb);
    #endif

    init_opts();

    if(verbose>=0)
    show_banner();

    /* parse options */
    parse_options(argc, argv, options, opt_output_file);

    if(nb_output_files <= 0 && nb_input_files == 0) {
    show_usage();
    fprintf(stderr, "Use -h to get full help or, even better, run 'man ffmpeg'n");
    ffmpeg_exit(1);
    }

    /* file converter / grab */
    if (nb_output_files <= 0) {
    fprintf(stderr, "At least one output file must be specifiedn");
    ffmpeg_exit(1);
    }

    if (nb_input_files == 0) {
    fprintf(stderr, "At least one input file must be specifiedn");
    ffmpeg_exit(1);
    }

    ti = getutime();
    if (transcode(output_files, nb_output_files, input_files, nb_input_files,
    stream_maps, nb_stream_maps) < 0)
    ffmpeg_exit(1);
    ti = getutime() - ti;
    if (do_benchmark) {
    int maxrss = getmaxrss() / 1024;
    printf("bench: utime=%0.3fs maxrss=%ikBn", ti / 1000000.0, maxrss);
    }

    return ffmpeg_exit(0);
    }

  7. Congratulations for the post, and for the application.

    Can you provide the full source code of this projetc (ffmpeg for Android Beta)? 😀

    Thanks.

    1. Please modify according to the post for now. It’s quite clear from my personal point of view.

      I’ll release the C part of the source code after some clean up. I’m currently busy with something else, will get it done after several weeks.

  8. ffmpeg.c:4624: error: no previous prototype for ‘Java_utm_fcim_BlaBlaActivity_mainn’
    What this mean? how to do your that?Please reply me

  9. What did you comment out in the ffmpeg.c to let it works with Android. Are you using the NDK to compile ffmpeg.c? I used the NDK to compile but i met some compile errors? Could you say more detail for what you commented out, please?

    Thanks

      1. Hey, thx roman very much!
        It’s very helpful that you also uploaded the code, but for some reason, when I tried it, it says “Error while opening encoder for output stream #0.1”
        I also tries the same cmd line (the default one) in the app from the play store and it’s work ok.
        Are there is any updates that you made?

        thx again.

      2. Hey, thx roman very much!
        It’s very helpful that you also uploaded the code, but for some reason, when I tried it, it says “Error while opening encoder for output stream #0.1”
        I also tries the same cmd line (the default one) in the app from the play store and it’s work ok.
        Are there is any updates that you made?

        thx again.

  10. Hi,

    i m using your code and able to run ffmpg commands, but i want to get callback that the command has been completed so that i can execute another command.

    i want to perform a sequence of commands one after another..

    please help me..

    thanks

Leave a Reply

Your email address will not be published. Required fields are marked *