FFmpeg на Android


207

Я получил FFmpeg (libffmpeg.so) на Android. Теперь мне нужно создать приложение вроде RockPlayer или использовать существующую мультимедийную среду Android для вызова FFmpeg.

  1. Есть ли у вас шаги / процедуры / код / ​​пример по интеграции FFmpeg на Android / StageFright?

  2. Подскажите, пожалуйста, как мне использовать эту библиотеку для воспроизведения мультимедиа?

  3. У меня есть требование, когда у меня уже есть аудио и видео транспортные потоки, которые мне нужно передать в FFmpeg и получить их декодирование / рендеринг. Как я могу сделать это на Android, поскольку API-интерфейсы IOMX основаны на OMX и не могут подключить FFmpeg здесь?

  4. Также я не смог найти документацию по API FFmpeg, которую нужно использовать для воспроизведения.


7
это интересно, мне тоже любопытно
Axarydax

5
как вы скомпилировали ffmpeg для получения файлов .so? Не могли бы вы поделиться своими действиями? Я работаю на Windows с Cygwin-1.7.9 и ndk R5. Пожалуйста, помогите мне.
Свати EP

Вот сравнительно новый FFmpeg для Android: sourceforge.net/projects/ffmpeg4android
slhck

@slhck Я скачал код ffmpeg по указанной выше ссылке и попытался скомпилировать его, но я не могу получить .so файлы. это показывает много проблем ..
RAJESH

пожалуйста, помогите мне с: stackoverflow.com/questions/14157030/… , я не знаю, где включить эту функцию и запустить! .....
TharakaNirmana

Ответы:


110

Вот шаги, которые я прошел, чтобы заставить ffmpeg работать на Android:

  1. Сборка статических библиотек ffmpeg для Android. Это было достигнуто путем создания порта Android ffmpeg ( libffmpeg ) от olvaffe с помощью Android Build System . Просто поместите источники в / внешний и makeпрочь. Вам также необходимо извлечь bionic (libc) и zlib (libz) из сборки Android, поскольку от них зависят библиотеки ffmpeg.
  2. Создайте динамическую библиотеку, упаковывающую функциональность ffmpeg, используя Android NDK . Там много документации о том, как работать с NDK. По сути, вам нужно написать некоторый код на C / C ++ для экспорта необходимой вам функциональности из ffmpeg в библиотеку, с которой java может взаимодействовать через JNI. NDK позволяет вам легко ссылаться на статические библиотеки, сгенерированные на шаге 1, просто добавьте строку, похожую на эту, в Android.mk:LOCAL_STATIC_LIBRARIES := libavcodec libavformat libavutil libc libz

  3. Используйте динамическую библиотеку ffmpeg из ваших java-источников. Там достаточно документации по JNI, у вас все должно быть в порядке.

Что касается использования ffmpeg для воспроизведения, есть много примеров (сам бинарный файл ffmpeg является хорошим примером), вот базовое руководство. Лучшая документация может быть найдена в заголовках.

Удачи :)


7
Есть несколько ссылок на этот ответ для сборки ffmpeg для Android. Это все еще лучшее решение? Ссылка Android Build System не работает - что это должно быть? Существует множество наборов инструментов, помогающих в построении с NDK. Однако они все терпят неудачу с различными ошибками сборки для меня, и кажутся немного старыми. Есть ли причина, по которой кто-то не может просто опубликовать встроенную статическую библиотеку ffmpeg?
Роб Лоуренс

7
Чтобы ответить на мой собственный вопрос, я обнаружил, что этот репозиторий наиболее полезен для создания оболочек ffmpeg и JNI - github.com/andynicholson/android-ffmpeg-x264
Роб Лоуренс

68

По разным причинам мультимедиа было и никогда не было легким с точки зрения решения задачи без ущерба для эффективности. ffmpeg - это попытка улучшить его изо дня в день. Поддерживаются разные форматы кодеков и контейнеров.

Теперь, чтобы ответить на вопрос, как использовать эту библиотеку , я бы сказал, что это не так просто написать здесь. Но я могу помочь вам следующими способами .

1) В каталоге исходного кода ffmpeg у вас есть output_example.c или api_example.c . Здесь вы можете увидеть код, в котором выполняется кодирование / декодирование. Вы получите представление о том, какой API внутри ffmpeg следует вызывать. Это будет ваш первый шаг.

2) Dolphin player - проект с открытым исходным кодом для Android. В настоящее время есть ошибки, но разработчики работают постоянно. В этом проекте у вас есть готовая настройка, которую вы можете использовать, чтобы продолжить расследование. Вот ссылка на проект с code.google.com или выполните команду « git clone https://code.google.com/p/dolphin-player/ » в терминале. Вы можете увидеть два проекта с именами P и P86. Вы можете использовать любой из них.

Дополнительный совет, который я хотел бы предложить, заключается в том, что при сборке кода ffmpeg внутри build.sh вам необходимо включить muxers / demuxers / encoders / decoders тех форматов, которые вы хотите использовать. В противном случае соответствующий код не будет включен в библиотеки. Мне потребовалось много времени, чтобы понять это. Мысль поделиться этим с вами.

Немного Основ: Когда мы говорим видеофайл, например: avi, это комбинация аудио и видео

Видео файл = Видео + Аудио


Видео = Кодек + Muxer + Demuxer

кодек = кодер + декодер

=> Видео = кодировщик + декодер + Muxer + Demuxer (Mpeg4 + Mpeg4 + avi + avi - пример для контейнера avi)


Аудио = Кодек + Muxer + Demuxer

кодек = кодер + декодер

=> Аудио = кодер + декодер + Muxer + Demuxer (mp2 + mp2 + avi + avi - пример для контейнера avi)


Кодек (имя происходит от комбинации en * co * der / * dec * oder) - это только часть формата, которая определяет алгоритмы, используемые для кодирования / декодирования кадра. AVI - это не кодек, это контейнер, который использует видеокодек Mpeg4 и аудиокодек mp2.

Muxer / demuxer используется для объединения / отделения кадров от файла, используемого при кодировании / декодировании.

Поэтому, если вы хотите использовать формат AVI, вам нужно включить компоненты Видео + Компоненты аудио.

Например, для avi необходимо включить следующее. Кодер mpeg4, декодер mpeg4, кодер mp2, декодер mp2, avi muxer, avi demuxer.

phewwwwwww ...

Программно build.sh должен содержать следующий код:

--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)

Надеюсь, я не смутил вас больше после всего этого ...

Спасибо, Любая помощь, пожалуйста, дайте мне знать.


1
Эй, я хотел бы поблагодарить вас за эту информацию, вы действительно очень мне помогли, возможно ли вам помочь мне, если мне понадобится немного позже? Спасибо!
идиш

Могу ли я добавить вас, пожалуйста, через Skype / MSN или любую другую платформу чата, пожалуйста? У меня есть несколько вопросов об этом, спасибо.
идиш

2
Конечно..!! Но мое присутствие в сети немного низкое. Если это не требуется, я не могу войти в Skype. Вы можете написать мне о любых важных вещах. Электронная почта: mantykuma@gmail.com
мк.

13

Самая простая в создании, простая в использовании реализация, которую я нашел, сделана командой guardianproject: https://github.com/guardianproject/android-ffmpeg


Не уверен, я предполагаю, что это так, ничто в новой версии iOS не приходит в голову, что могло бы сломать это. Когда я писал это, у меня все еще было 10,7 или 10,6
Гай

Знаете ли вы, как я могу конвертировать 3gp в аудио, используя реализацию JNI
Mr.G

11

Я сделал небольшой проект по настройке и сборке X264 и FFMPEG с помощью Android NDK. Главное, чего не хватает, - это достойного интерфейса JNI, чтобы сделать его доступным через Java, но это самая простая часть (относительно). Когда я подойду к созданию интерфейса JNI, подходящего для моих собственных нужд, я настаиваю на этом.

Преимущество над системой сборки olvaffe заключается в том, что для сборки библиотек ей не нужны файлы Android.mk, она просто использует обычные make-файлы и набор инструментов. Это значительно снижает вероятность прекращения работы при извлечении нового изменения из FFMPEG или X264.

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


Ник, ваш проект не компилируется в OS X 10.7 libx264.a (common.o): В функции x264_param_parse': common.c:(.text+0x2864): undefined reference to _DefaultRuneLocale 'collect2: ld возвращено 1 состояние завершения make: *** [x264] Ошибка 1
Юрий Соловьев

9

После долгих исследований, сейчас это самая обновленная скомпилированная библиотека для Android, которую я нашел:

https://github.com/bravobit/FFmpeg-Android

  • В данный момент используется FFmpeg release n4.0-39-gda39990
  • Включает FFmpeg и FFProbe
  • Содержит интерфейс Java для запуска команд
  • FFprobe или FFmpeg могут быть удалены из APK, проверьте вики https://github.com/bravobit/FFmpeg-Android/wiki

6

Для создания своего приложения FFMPEG я использовал этот проект ( https://github.com/hiteshsondhi88/ffmpeg-android-java ), поэтому мне не нужно ничего компилировать. Я думаю, что это простой способ использовать FFMPEG в наших приложениях для Android.

Более подробная информация на http://hiteshsondhi88.github.io/ffmpeg-android-java/


3
Эта обертка очень, очень, очень, очень, очень медленно. 200 изображений на видео занимает 50-60 секунд. , , но обычно ffmpeg выполняет эту задачу за 4-5 секунд.
Арсен Сенч

Этот проект больше не работает. У вас есть другие ресурсы?
Ajeet

@ArsenSench у тебя есть другое решение?
Акаш Дубей

3

Вдохновленный многими другими реализациями FFmpeg для Android (в основном guadianproject ), я нашел решение (также с поддержкой Lame).

(Хромой и FFmpeg: https://github.com/intervigilium/liblame и http://bambuser.com/opensource )

позвонить в 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();

и обработать вывод консоли:

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.
        }
    }
}

Какой у вас опыт работы с guardianproject?
XY

3

Странно, что этот проект не был упомянут: AndroidFFmpeg от Appunite

Там есть довольно подробные пошаговые инструкции для копирования / вставки в командную строку, для ленивых людей, как я))


3

У меня была та же проблема, я нашел здесь большинство ответов от. В итоге я написал оболочку на FFMPEG для доступа из Android с помощью одной строки кода.

https://github.com/madhavanmalolan/ffmpegandroidlibrary


1
Кажется, вы собрали FFmpeg v2.8.4, есть ли планы по обновлению FFmpeg? Мы ищем решение для Android, имеющее самую последнюю (может быть 3.2 или 3.4) версию FFmpeg.
Саппу

Да. Я намерен переместить его в 3.x github.com/madhavanmalolan/ffmpegandroidlibrary/milestone/1. Вы можете попробовать изменить скрипт сборки здесь и скомпилировать для 3.4 github.com/madhavanmalolan/ffmpegandroidlibrary/wiki/…
Мадхаван Малолан,

Спасибо @Madhvan. Я строю библиотеку ffmpeg на окнах. Просто интересно, что все нужно изменить в github.com/madhavanmalolan/ffmpegandroidlibrary/wiki/… , чтобы построить?
Саппу

1

Сначала добавьте зависимость библиотеки FFmpeg

implementation 'com.writingminds:FFmpegAndroid:0.3.2'

Тогда нагрузка в деятельности

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();

}

Также используйте другую функцию от 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()
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.