FFmpeg di Android

207

Saya mendapatkan FFmpeg yang dikompilasi (libffmpeg.so) di Android. Sekarang saya harus membuat aplikasi seperti RockPlayer atau menggunakan kerangka kerja multimedia Android yang ada untuk menjalankan FFmpeg.

  1. Apakah Anda memiliki langkah / prosedur / kode / contoh tentang mengintegrasikan FFmpeg di Android / StageFright?

  2. Bisakah Anda membimbing saya tentang bagaimana saya bisa menggunakan perpustakaan ini untuk pemutaran multimedia?

  3. Saya memiliki persyaratan di mana saya sudah memiliki stream transportasi audio dan video, yang perlu saya beri makan ke FFmpeg dan mendapatkannya diterjemahkan / dirender. Bagaimana saya bisa melakukan ini di Android, karena API IOMX berbasis OMX dan tidak dapat plug-in FFmpeg di sini?

  4. Juga saya tidak dapat menemukan dokumentasi tentang API FFmpeg yang perlu digunakan untuk pemutaran.

Perasaan
sumber
7
ini menarik, saya juga penasaran
Axarydax
5
bagaimana Anda mengkompilasi ffmpeg untuk mendapatkan file .so? dapatkah Anda membagikan langkah-langkah yang Anda ikuti. Saya bekerja di windows dengan cygwin-1.7.9 dan ndk r5. Tolong bantu aku.
Swathi EP
Inilah FFmpeg yang relatif baru untuk Android: sourceforge.net/projects/ffmpeg4android
slhck
@slhck saya telah mengunduh kode ffmpeg dari tautan di atas dan telah mencoba untuk mengompilasinya tetapi saya tidak bisa mendapatkan file .so. itu menunjukkan banyak masalah ..
RAJESH
tolong bantu saya dengan: stackoverflow.com/questions/14157030/… , saya tidak tahu di mana harus memasukkan fungsi ini dan jalankan! .....
TharakaNirmana

Jawaban:

109

Berikut adalah langkah-langkah yang saya lalui dalam mendapatkan ffmpeg untuk bekerja di Android:

  1. Buat pustaka statis ffmpeg untuk Android. Ini dicapai dengan membangun port android ffmpeg olvaffe ( libffmpeg ) menggunakan Android Build System . Cukup tempatkan sumber di bawah / eksternal dan makejauh. Anda perlu mengekstrak bionik (libc) dan zlib (libz) dari Android build juga, karena pustaka ffmpeg bergantung padanya.
  2. Buat pustaka dinamis yang membungkus fungsionalitas ffmpeg menggunakan Android NDK . Ada banyak dokumentasi di luar sana tentang cara bekerja dengan NDK. Pada dasarnya Anda harus menulis beberapa kode C / C ++ untuk mengekspor fungsionalitas yang Anda butuhkan dari ffmpeg ke perpustakaan yang dapat berinteraksi dengan java melalui JNI. NDK memungkinkan Anda untuk dengan mudah menautkan pustaka statis yang Anda buat pada langkah 1, cukup tambahkan baris yang mirip dengan ini ke Android.mk:LOCAL_STATIC_LIBRARIES := libavcodec libavformat libavutil libc libz

  3. Gunakan pustaka dinamis pembungkus ffmpeg dari sumber java Anda. Ada cukup dokumentasi tentang JNI di luar sana, Anda harus baik-baik saja.

Mengenai menggunakan ffmpeg untuk pemutaran, ada banyak contoh (biner ffmpeg itu sendiri adalah contoh yang baik), inilah tutorial dasar. Dokumentasi terbaik dapat ditemukan di header.

Semoga berhasil :)

yonilevy
sumber
7
Ada beberapa tautan ke jawaban ini untuk membuat ffmpeg untuk Android. Apakah ini masih solusi terbaik? Tautan Android Build System rusak - apa yang seharusnya? Ada banyak toolkit untuk membantu membangun dengan NDK. Namun mereka semua gagal dengan berbagai kesalahan build untuk saya, dan tampak agak tua. Apakah ada alasan mengapa seseorang tidak bisa begitu saja mengirim lib ffmpeg statis bawaan?
Rob Lourens
7
Untuk menjawab pertanyaan saya sendiri, saya menemukan repo ini menjadi yang paling berguna untuk membangun pembungkus ffmpeg dan JNI - github.com/andynicholson/android-ffmpeg-x264
Rob Lourens
68

Karena berbagai alasan, Multimedia dulu dan tidak pernah mudah dalam hal mencapai tugas tanpa mengorbankan efisiensi. ffmpeg adalah upaya meningkatkannya dari hari ke hari. Ini mendukung berbagai format codec dan wadah.

Sekarang untuk menjawab pertanyaan tentang bagaimana menggunakan perpustakaan ini , saya akan mengatakan bahwa tidak mudah untuk menulisnya di sini. Tapi saya bisa membimbing Anda dengan cara berikut .

1) Di dalam direktori ffmpeg kode sumber, Anda memiliki output_example.c atau api_example.c . Di sini, Anda dapat melihat kode di mana pengkodean / decoding dilakukan. Anda akan mendapatkan gagasan tentang ffmpeg API mana yang harus Anda panggil. Ini akan menjadi langkah pertama Anda.

2) Dolphin player adalah proyek sumber terbuka untuk Android. Saat ini sedang mengalami bug tetapi pengembang bekerja terus menerus. Dalam proyek itu Anda memiliki seluruh pengaturan yang siap yang dapat Anda gunakan untuk melanjutkan penyelidikan Anda. Berikut ini tautan ke proyek dari code.google.com atau jalankan perintah " git clone https://code.google.com/p/dolphin-player/ " di terminal. Anda dapat melihat dua proyek bernama P dan P86. Anda bisa menggunakan keduanya.

Kiat tambahan yang ingin saya tawarkan adalah bahwa ketika Anda sedang membangun kode ffmpeg, di dalam build.sh Anda perlu mengaktifkan muxers / demuxers / encoders / decoder dari format yang ingin Anda gunakan. Jika tidak, kode yang sesuai tidak akan disertakan dalam perpustakaan. Butuh banyak waktu bagi saya untuk menyadari hal ini. Jadi pikirkan untuk membaginya dengan Anda.

Beberapa Dasar-Dasar: Ketika kita mengatakan file video, mis: avi, itu adalah kombinasi dari audio dan video

File video = Video + Audio


Video = Codec + Muxer + Demuxer

codec = encoder + Decoder

=> Video = encoder + decoder + Muxer + Demuxer (Mpeg4 + Mpeg4 + avi + avi - Contoh untuk wadah avi)


Audio = Codec + Muxer + Demuxer

codec = encoder + Decoder

=> Audio = encoder + decoder + Muxer + Demuxer (mp2 + mp2 + avi + avi - Contoh untuk wadah avi)


Codec (nama adalah deriverd dari kombinasi en * co * der / * dec * oder) hanyalah bagian dari format yang mendefinisikan algoritma yang digunakan untuk menyandikan / mendekodekan sebuah frame. AVI bukan codec, ini adalah wadah yang menggunakan codec Video Mpeg4 dan Audio codec dari mp2.

Muxer / demuxer digunakan untuk menggabungkan / memisahkan frame dari file yang digunakan saat encoding / decoding.

Jadi jika Anda ingin menggunakan format avi, Anda harus mengaktifkan komponen Video + komponen Audio.

Misalnya, untuk avi, Anda harus mengaktifkan yang berikut ini. mpeg4 Encoder, mpeg4 decoder, mp2 encoder, mp2 decoder, avi muxer, avi demuxer.

phewwwwwww ...

Secara pemrograman build.sh harus berisi kode berikut:

--enable-muxer=avi --enable-demuxer=avi (Generic for both audio/video. generally Specific to a container)
--enable-encoder=mpeg4 --enable-decoder=mpeg4(For video support)
--enable-encoder=mp2 --enable-decoder=mp2 (For Audio support)

Semoga saya idid tidak membingungkan Anda lagi setelah semua ini ...

Terima kasih, Setiap bantuan yang diperlukan, harap beri tahu saya.

mk ..
sumber
1
Hai, saya ingin mengucapkan terima kasih banyak atas info itu, Anda benar-benar banyak membantu saya, Apakah mungkin bagi Anda untuk membantu saya jika saya membutuhkan nanti? Terima kasih!
idish
Bisakah saya menambahkan Anda melalui skype / MSN atau platform obrolan lainnya? Saya punya beberapa pertanyaan tentang itu, terima kasih.
idish
2
Tentu..!! Tetapi kehadiran online saya agak rendah .. Kecuali sangat diperlukan saya tidak masuk ke skype. Anda dapat mengirim saya email untuk hal-hal penting. Email: [email protected]
mk ..
13

Implementasi yang paling mudah dibangun, mudah digunakan yang saya temukan dibuat oleh tim theguardianproject: https://github.com/guardianproject/android-ffmpeg

Orang
sumber
Tidak yakin, saya menduga itu adalah, tidak ada dalam versi iOS baru yang terlintas dalam pikiran yang mungkin mematahkan ini. Ketika saya memposting ini, saya masih punya 10,7 atau 10,6
Guy
apakah Anda tahu, bagaimana saya bisa mengkonversi 3gp ke audio, menggunakan implementasi JNI
Mr.G
11

Saya telah melakukan sedikit proyek untuk mengonfigurasi dan membangun X264 dan FFMPEG menggunakan Android NDK. Hal utama yang hilang adalah antarmuka JNI yang layak untuk membuatnya dapat diakses melalui Java, tetapi itu adalah bagian yang mudah (relatif). Ketika saya mencoba membuat antarmuka JNI baik untuk keperluan saya sendiri, saya akan mendorongnya.

Keuntungan dari sistem build olvaffe adalah tidak memerlukan file Android.mk untuk membangun perpustakaan, hanya menggunakan makefile biasa dan toolchain. Ini membuatnya jauh lebih kecil kemungkinannya untuk berhenti bekerja ketika Anda menarik perubahan baru dari FFMPEG atau X264.

https://github.com/halfninja/android-ffmpeg-x264

Nick
sumber
Nick, proyek Anda tidak dikompilasi pada OS X 10.7 libx264.a (common.o): Dalam fungsi x264_param_parse': common.c:(.text+0x2864): undefined reference to _DefaultRuneLocale 'collect2: ld mengembalikan 1 status keluar make: *** [x264] Kesalahan 1
Yuriy Solovyov
6

Untuk membuat aplikasi FFMPEG saya, saya menggunakan proyek ini ( https://github.com/hiteshsondhi88/ffmpeg-android-java ) jadi, saya tidak perlu mengkompilasi apa pun. Saya pikir ini cara mudah untuk menggunakan FFMPEG di aplikasi Android kami.

Info lebih lanjut tentang http://hiteshsondhi88.github.io/ffmpeg-android-java/

jmartinalonso
sumber
3
Wrapper ini sangat sangat sangat sangat sangat lambat. 200 gambar ke video membutuhkan 50-60 detik. . . tetapi biasanya ffmpeg menangani tugas itu dalam 4-5 detik.
Arsen Sench
Proyek ini tidak berfungsi lagi. Apakah Anda memiliki sumber daya lain?
Ajeet
@ ArsenSench Anda punya solusi lain?
Akash Dubey
3

Terinspirasi oleh banyak FFmpeg lain pada implementasi Android di luar sana (terutama proyek guadian ), saya menemukan solusi (dengan dukungan Lame juga).

(lumpuh dan FFmpeg: https://github.com/intervigilium/liblame dan http://bambuser.com/opensource )

untuk memanggil FFmpeg:

new Thread(new Runnable() {

    @Override
    public void run() {

        Looper.prepare();

        FfmpegController ffmpeg = null;

        try {
            ffmpeg = new FfmpegController(context);
        } catch (IOException ioe) {
            Log.e(DEBUG_TAG, "Error loading ffmpeg. " + ioe.getMessage());
        }

        ShellDummy shell = new ShellDummy();
        String mp3BitRate = "192";

        try {
            ffmpeg.extractAudio(in, out, audio, mp3BitRate, shell);
        } catch (IOException e) {
            Log.e(DEBUG_TAG, "IOException running ffmpeg" + e.getMessage());
        } catch (InterruptedException e) {
            Log.e(DEBUG_TAG, "InterruptedException running ffmpeg" + e.getMessage());
        }

        Looper.loop();

    }

}).start();

dan untuk menangani output konsol:

private class ShellDummy implements ShellCallback {

    @Override
    public void shellOut(String shellLine) {
        if (someCondition) {
            doSomething(shellLine);
        }
        Utils.logger("d", shellLine, DEBUG_TAG);
    }

    @Override
    public void processComplete(int exitValue) {
        if (exitValue == 0) {
            // Audio job OK, do your stuff: 

                            // i.e.             
                            // write id3 tags,
                            // calls the media scanner,
                            // etc.
        }
    }

    @Override
    public void processNotStartedCheck(boolean started) {
        if (!started) {
                            // Audio job error, as above.
        }
    }
}
dentex
sumber
Apa pengalaman Anda dengan proyek wali?
XY
3

Aneh bahwa proyek ini belum disebutkan: AndroidFFmpeg dari Appunite

Ini memiliki petunjuk langkah-demi-langkah yang cukup rinci untuk menyalin / menempel ke baris perintah, untuk orang malas seperti saya))

Mixaz
sumber
3

Saya memiliki masalah yang sama, saya menemukan sebagian besar jawaban di sini keluar. Saya akhirnya menulis bungkus pada FFMPEG untuk diakses dari Android dengan satu baris kode.

https://github.com/madhavanmalolan/ffmpegandroidlibrary

Madhavan Malolan
sumber
1
Sepertinya Anda telah mengompilasi FFmpeg v2.8.4, apakah ada rencana untuk memutakhirkan FFmpeg? Kami sedang mencari solusi android yang memiliki FFmpeg versi terbaru (mungkin 3.2 atau 3.4).
sappu
Iya. Saya bermaksud memindahkannya ke 3.x github.com/madhavanmalolan/ffmpegandroidlibrary/milestone/1 Anda dapat mencoba untuk memodifikasi skrip build di sini dan kompilasi untuk 3.4 github.com/madhavanmalolan/ffmpegandroidlibrary/wiki/…
Madhavan Malolan
Terima kasih @Madhvan. Saya sedang membangun perpustakaan ffmpeg di windows. Hanya ingin tahu apa yang perlu diubah di github.com/madhavanmalolan/ffmpegandroidlibrary/wiki/… untuk membangun?
sappu
1

Pertama, tambahkan dependensi library FFmpeg

implementation 'com.writingminds:FFmpegAndroid:0.3.2'

Kemudian muat dalam aktivitas

FFmpeg ffmpeg;
    private void trimVideo(ProgressDialog progressDialog) {

    outputAudioMux = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES).getAbsolutePath()
            + "/VidEffectsFilter" + "/" + new SimpleDateFormat("ddMMyyyy_HHmmss").format(new Date())
            + "filter_apply.mp4";

    if (startTrim.equals("")) {
        startTrim = "00:00:00";
    }

    if (endTrim.equals("")) {
        endTrim = timeTrim(player.getDuration());
    }

    String[] cmd = new String[]{"-ss", startTrim + ".00", "-t", endTrim + ".00", "-noaccurate_seek", "-i", videoPath, "-codec", "copy", "-avoid_negative_ts", "1", outputAudioMux};


    execFFmpegBinary1(cmd, progressDialog);
    }



    private void execFFmpegBinary1(final String[] command, ProgressDialog prpg) {

    ProgressDialog progressDialog = prpg;

    try {
        ffmpeg.execute(command, new ExecuteBinaryResponseHandler() {
            @Override
            public void onFailure(String s) {
                progressDialog.dismiss();
                Toast.makeText(PlayerTestActivity.this, "Fail to generate video", Toast.LENGTH_SHORT).show();
                Log.d(TAG, "FAILED with output : " + s);
            }

            @Override
            public void onSuccess(String s) {
                Log.d(TAG, "SUCCESS wgith output : " + s);

//                    pathVideo = outputAudioMux;
                String finalPath = outputAudioMux;
                videoPath = outputAudioMux;
                Toast.makeText(PlayerTestActivity.this, "Storage Path =" + finalPath, Toast.LENGTH_SHORT).show();

                Intent intent = new Intent(PlayerTestActivity.this, ShareVideoActivity.class);
                intent.putExtra("pathGPU", finalPath);
                startActivity(intent);
                finish();
                MediaScannerConnection.scanFile(PlayerTestActivity.this, new String[]{finalPath}, new String[]{"mp4"}, null);

            }

            @Override
            public void onProgress(String s) {
                Log.d(TAG, "Started gcommand : ffmpeg " + command);
                progressDialog.setMessage("Please Wait video triming...");
            }

            @Override
            public void onStart() {
                Log.d(TAG, "Startedf command : ffmpeg " + command);

            }

            @Override
            public void onFinish() {
                Log.d(TAG, "Finished f command : ffmpeg " + command);
                progressDialog.dismiss();
            }
        });
    } catch (FFmpegCommandAlreadyRunningException e) {
        // do nothing for now
    }
}

  private void loadFFMpegBinary() {
    try {
        if (ffmpeg == null) {
            ffmpeg = FFmpeg.getInstance(this);
        }
        ffmpeg.loadBinary(new LoadBinaryResponseHandler() {
            @Override
            public void onFailure() {
                showUnsupportedExceptionDialog();
            }

            @Override
            public void onSuccess() {
                Log.d("dd", "ffmpeg : correct Loaded");
            }
        });
    } catch (FFmpegNotSupportedException e) {
        showUnsupportedExceptionDialog();
    } catch (Exception e) {
        Log.d("dd", "EXception no controlada : " + e);
    }
}

private void showUnsupportedExceptionDialog() {
    new AlertDialog.Builder(this)
            .setIcon(android.R.drawable.ic_dialog_alert)
            .setTitle("Not Supported")
            .setMessage("Device Not Supported")
            .setCancelable(false)
            .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    finish();
                }
            })
            .create()
            .show();

}

Juga gunakan fitur lain oleh FFmpeg

===> merge audio to video
String[] cmd = new String[]{"-i", yourRealPath, "-i", arrayList.get(posmusic).getPath(), "-map", "1:a", "-map", "0:v", "-codec", "copy", "-shortest", outputcrop};


===> Flip vertical :
String[] cm = new String[]{"-i", yourRealPath, "-vf", "vflip", "-codec:v", "libx264", "-preset", "ultrafast", "-codec:a", "copy", outputcrop1};


===> Flip horizontally :  
String[] cm = new String[]{"-i", yourRealPath, "-vf", "hflip", "-codec:v", "libx264", "-preset", "ultrafast", "-codec:a", "copy", outputcrop1};


===> Rotate 90 degrees clockwise:
String[] cm=new String[]{"-i", yourRealPath, "-c", "copy", "-metadata:s:v:0", "rotate=90", outputcrop1};


===> Compress Video
String[] complexCommand = {"-y", "-i", yourRealPath, "-strict", "experimental", "-vcodec", "libx264", "-preset", "ultrafast", "-crf", "24", "-acodec", "aac", "-ar", "22050", "-ac", "2", "-b", "360k", "-s", "1280x720", outputcrop1};


===> Speed up down video
String[] complexCommand = {"-y", "-i", yourRealPath, "-filter_complex", "[0:v]setpts=2.0*PTS[v];[0:a]atempo=0.5[a]", "-map", "[v]", "-map", "[a]", "-b:v", "2097k", "-r", "60", "-vcodec", "mpeg4", outputcrop1};
String[] complexCommand = {"-y", "-i", yourRealPath, "-filter_complex", "[0:v]setpts=1.0*PTS[v];[0:a]atempo=1.0[a]", "-map", "[v]", "-map", "[a]", "-b:v", "2097k", "-r", "60", "-vcodec", "mpeg4", outputcrop1};
String[] complexCommand = {"-y", "-i", yourRealPath, "-filter_complex", "[0:v]setpts=0.75*PTS[v];[0:a]atempo=1.5[a]", "-map", "[v]", "-map", "[a]", "-b:v", "2097k", "-r", "60", "-vcodec", "mpeg4", outputcrop1};
String[] complexCommand = {"-y", "-i", yourRealPath, "-filter_complex", "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]", "-map", "[v]", "-map", "[a]", "-b:v", "2097k", "-r", "60", "-vcodec", "mpeg4", outputcrop1};



===> Add two mp3 files 

StringBuilder sb = new StringBuilder();
sb.append("-i ");
sb.append(textSngname);
sb.append(" -i ");
sb.append(mAudioFilename);
sb.append(" -filter_complex [0:0][1:0]concat=n=2:v=0:a=1[out] -map [out] ");
sb.append(finalfile);
---> ffmpeg.execute(sb.toString().split(" "), new ExecuteBinaryResponseHandler()




===> Add three mp3 files

StringBuilder sb = new StringBuilder();
sb.append("-i ");
sb.append(firstSngname);
sb.append(" -i ");
sb.append(textSngname);
sb.append(" -i ");
sb.append(mAudioFilename);
sb.append(" -filter_complex [0:0][1:0][2:0]concat=n=3:v=0:a=1[out] -map [out] ");
sb.append(finalfile);
---> ffmpeg.execute(sb.toString().split(" "), new ExecuteBinaryResponseHandler()
jay patoliya
sumber