Быстрое сжатие видео, как в Whatsapp

Мне нужно ускорить сжатие видео в моем приложении для Android. Я использую FFMPEG, и для сжатия видео размером 80 МБ требуется 3 минуты. Кто-нибудь знает лучшее решение?

Я использую команду:

/data/data/com.moymer/app_bin/ffmpeg -y -i /storage/emulated/0/DCIM/Camera/VID_20150803_164811363.mp4 -s 640x352 -r 25 -vcodec mpeg4 -ac 1 -preset ultrafast -strict -2 /storage/emulated/0/DCIM/Camera/compressed_video.mp4

Я запускаю эту команду с помощью FFMPEG для Android из этого репозитория github: https://github.com/guardianproject/android-ffmpeg-java

Код для использования FFMPEG в моем проекте находится внутри AsyncTask и скопирован ниже:

@Override
protected Object doInBackground(Object... params) {

    ItemRoloDeCamera compressedVideo = new ItemRoloDeCamera();

    File videoInputFile = new File(video.getSdcardPath());

    File videoFolderFile = videoInputFile.getParentFile();

    File videoOutputFile = new File(videoFolderFile, "video_comprimido_moymer.mp4");

    if (videoFolderFile.exists())
        android.util.Log.e("COMPRESS VIDEO UTILS", "video folder exist");
    else
        android.util.Log.e("COMPRESS VIDEO UTILS", "video folder DON'T exist");

    if (videoInputFile.exists())
        android.util.Log.e("COMPRESS VIDEO UTILS", "video input file exist");
    else
        android.util.Log.e("COMPRESS VIDEO UTILS", "video input file DON'T exist");

    if (videoOutputFile.exists())
        android.util.Log.e("COMPRESS VIDEO UTILS", "video output file exist");
    else
        android.util.Log.e("COMPRESS VIDEO UTILS", "video output file DON'T exist");

    FfmpegController ffmpegController;

    try {

        ffmpegController = new FfmpegController(context, videoFolderFile);

        Clip clipIn = new Clip(videoInputFile.getAbsolutePath());

        ffmpegController.getInfo(clipIn, new ShellUtils.ShellCallback() {
            @Override
            public void shellOut(String shellLine) {
                videoInfo.add(shellLine);
            }

            @Override
            public void processComplete(int exitValue) {
                videoInfo.add(String.valueOf(exitValue));
            }
        });

        int rotate = getRotateMetadata();

        Clip clipOut = new Clip(videoOutputFile.getAbsolutePath());
        clipOut.videoFps = "24";
        clipOut.videoBitrate = 512;
        clipOut.audioChannels = 1;
        clipOut.width = 640;
        clipOut.height = 352;

        if (rotate == 90)
            clipOut.videoFilter = "transpose=1";
        else if (rotate == 180)
            clipOut.videoFilter = "transpose=1,transpose=1";
        else if (rotate == 270)
            clipOut.videoFilter = "transpose=1,transpose=1,transpose=1";

        millisDuration = getVideoDuration(videoInputFile.getAbsolutePath());

        float secondsDuration = millisDuration / 1000f;

        clipOut.duration = secondsDuration;

        ffmpegController.processVideo(clipIn, clipOut, true, new ShellUtils.ShellCallback() {
            @Override
            public void shellOut(String shellLine) {

                android.util.Log.e("COMPRESS VIDEO UTILS", "shellOut - " + shellLine);

                float percentage = getTimeMetadata(shellLine);

                if (percentage >= 0f)
                    publishProgress(percentage);

            }

            @Override
            public void processComplete(int exitValue) {
                android.util.Log.e("COMPRESS VIDEO UTILS", "proccess complete - " + exitValue);
            }
        });


    } catch (IOException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {

        if (videoOutputFile.exists()) {

            android.util.Log.e("COMPRESS VIDEO UTILS", "finished ffmpeg ---> video output file exist");

            compressedVideo.setSdcardPath(videoOutputFile.getAbsolutePath());

            return compressedVideo;

        } else
            android.util.Log.e("COMPRESS VIDEO UTILS", "finished ffmpeg ---> video output file DON'T exist");

    }

    return compressedVideo;

}

private float getTimeMetadata(String shellLine) {

    float percentage = -1;

    if (shellLine.contains("time=")) {

        String[] timeLine = shellLine.split("=");

        String time = timeLine[5];
        time = time.replace("bitrate", "");
        time = time.trim();

    //            String source = "00:10:17";
        String[] tokens = time.split(":");
        int secondsToMs = (int) (Float.parseFloat(tokens[2]) * 1000);
        int minutesToMs = Integer.parseInt(tokens[1]) * 60000;
        int hoursToMs = Integer.parseInt(tokens[0]) * 3600000;
        long timeInMillis = secondsToMs + minutesToMs + hoursToMs;

        percentage = (timeInMillis * 100.0f) / millisDuration;

    }

    return percentage;

}

private int getRotateMetadata() {

    int rotate = 0;

    String durationString = "";

    for (String shellLine : videoInfo) {

        if (shellLine.contains("rotate")) {

            //rotate          : 270

            String[] rotateLine = shellLine.split(":");

            rotate = Integer.parseInt(rotateLine[1].trim());

        }

    }

    return rotate;

}

public static long getVideoDuration(String videoPath) {

    MediaMetadataRetriever retriever = new MediaMetadataRetriever();

    retriever.setDataSource(videoPath);

    String time = retriever
            .extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);

    long timeInmillisec = Long.parseLong(time);

    return timeInmillisec;

}

Единственное изменение, которое я внес в метод processVideo, заключалось в добавлении следующих строк при построении команды:

cmd.add("-preset");
cmd.add("ultrafast");

person Douglas Anunciação    schedule 03.08.2015    source источник
comment
проверьте этот ответ на суперпользователе, superuser.com/a/792609   -  person petey    schedule 04.08.2015
comment
Но @petey я перепробовал все возможные номера потоков и не меняю скорость сжатия.   -  person Douglas Anunciação    schedule 04.08.2015
comment
Я никогда не запускал ffmpeg на Android. При этом я ничуть не удивлен, что он работает медленно, учитывая плохие характеристики флэш-памяти на многих устройствах Android. Вместо того, чтобы преобразовывать видео на устройстве, я бы сосредоточился на том, чтобы сделать видео ближе к тому, как вы хотите, и, возможно, использовать сервер для любых последних штрихов.   -  person CommonsWare    schedule 05.08.2015
comment
@DouglasAnunciação, вы нашли способ улучшить скорость? Поделись, пожалуйста. Я застрял в том же здесь.   -  person Asif Aminur Rashid    schedule 29.10.2015
comment
@DouglasAnunciação Вы нашли какое-нибудь решение этой проблемы, у меня такая же проблема со сжатием видео. Спасибо!   -  person Bahramdun Adil    schedule 30.08.2016