Объединение файлов mp4 в Android с помощью halfninja ffmpeg

Мне удалось скомпилировать скрипты halfninja ffmpeg для Android NDK, используя NDK версии r5c. (К сожалению, любая попытка компиляции с более ранним NDK приводила к некоторым ошибкам), также я не очень хорошо разбираюсь во всем процессе NDK, поэтому для меня это немного случайность.

Его скрипты компилируют версию ffmpeg N-30996-gf925b24 (конкретный коммит, для которого он делал скрипты)

Двигаясь вперед к моему реальному приложению. Мне удается обрезать видео без проблем, теперь мне нужно их соединить/объединить, но любая попытка использования любой и нескольких комбинаций команд, найденных по этим 3 ссылкам (ссылка1, ссылка2, link3) вызывают такие ошибки, как как cat is not valid, > is undefinined, unknown option filter_complex или пытается переопределить некоторые входные файлы.

Кто-нибудь знает, возможно ли и (как это сделать) объединять/объединять mp4-видео (все тот же кодек, размер, качество и т. д.), используя полуниндзя-компиляцию ffmpeg на Android, или как скомпилировать/получить ffmpeg для Android с использованием последних исходных кодов?

Я также быстро попробовал mp4Parser, но без особого успеха.

в конечном итоге я пытался заставить этот псевдометод работать:

public static File concatenate(String[] inputPaths, String outputPath){

    // ... do stuff do generate ffmpeg commands....
    VideoKit v = new VideoKit();
    v.run(cmds);

    File f = new File(outputPath);
    return f;
}

person Budius    schedule 19.04.2013    source источник
comment
мне удалось скомпилировать проект наполовину ниндзя, но теперь я хочу сжать большие видеофайлы, но прежде всего я попытался получить звук из аудиофайла, к сожалению, команда запуска не работает, выдает следующую ошибку, 12-20 13:31: 26.958: W/ActivityManager(290): Принудительное удаление ActivityRecord{2c0322f0 uk.co.halfninja.videokit/.MainActivity}: приложение умерло, нет сохраненного состояния по какой-либо конкретной причине??   -  person Mr.G    schedule 20.12.2013


Ответы (5)


Ответ, предоставленный LordNeckbeard, действительно правильный.

Как объединить FLV-файл в один?

Работа с вашими ограничениями

  • no -f concat
  • no -c
  • no -bsf
ffmpeg -i q.mp4 -vcodec copy -acodec copy -vbsf h264_mp4toannexb q.ts
ffmpeg -i r.mp4 -vcodec copy -acodec copy -vbsf h264_mp4toannexb r.ts
ffmpeg -i 'concat:q.ts|r.ts' -vcodec copy -acodec copy -absf aac_adtstoasc qr.mp4

Присоединение к H264 *без* повторного кодирования

person Steven Penny    schedule 23.04.2013
comment
Привет. У меня как раз есть попытка на этом. -c всегда терпит неудачу, я заменил на -vcodec и -acodec, затем он дал мне Unrecognised option bsf, а затем без bsf я получил av_interleaved_write_frame(): Operation not permitted. Я попробую комментарий @Robert Rowntree, чтобы использовать эту тему stackoverflow.com/questions/12817198/ffmpeg-1-0-android-ndk-r8b, но это займет у меня некоторое время, потому что 1) это личный проект, который я делаю в своем бесплатном время, и я переезжаю по стране, поэтому свободного времени не будет в ближайшее время и 2) пока я не соберусь с этим и не пойму, что происходит со всеми командами. - person Budius; 25.04.2013
comment
привет, Стив, я очень рад, что ты заработал половину / награду, так как я мог видеть твои усилия, и я действительно очень ценю это. К сожалению, моя жизнь решила немного перевернуться с ног на голову, потому что я переезжаю по стране и просто не могу это проверить. Но обязательно протестирую и сообщу. Также, если/когда мне удастся заставить что-то работать, я отвечу. - person Budius; 30.04.2013

эта последовательность будет отображать mp4 в CLI. это со страницы часто задаваемых вопросов ffmpeg о конкатенации...

$FFMPEG_HOME/ffmpeg  -i gpsclip_seg1.mp4  -vn -f u16le -acodec pcm_s16le -ac 1 -ar 44100 - > temp1.a < /dev/null
$FFMPEG_HOME/ffmpeg  -i gpsclip_seg2.mp4  -vn -f u16le -acodec pcm_s16le -ac 1 -ar 44100 - > temp2.a < /dev/null
$FFMPEG_HOME/ffmpeg  -i gpsclip_seg3.mp4  -vn -f u16le -acodec pcm_s16le -ac 1 -ar 44100 - > temp3.a < /dev/null
cat temp1.a temp2.a temp3.a > all.a

$FFMPEG_HOME/ffmpeg -i gpsclip_seg1.mp4 -an -f yuv4mpegpipe - > temp1.v < /dev/null &
$FFMPEG_HOME/ffmpeg -i gpsclip_seg2.mp4 -an -f yuv4mpegpipe - < /dev/null | tail -n +2 > temp2.v
$FFMPEG_HOME/ffmpeg -i gpsclip_seg3.mp4 -an -f yuv4mpegpipe - < /dev/null | tail -n +2 > temp3.v
cat temp1.v temp2.v temp3.v > all.v

$FFMPEG_HOME/ffmpeg -f u16le -acodec pcm_s16le -ac 1 -ar 44100 -i all.a -f yuv4mpegpipe -i all.v -same_quant -y output.mp4

Я посмотрел на «Android.mk» от Halfninja ... и для тестирования вы должны иметь возможность использовать adb для отправки исполняемого файла «ffmpeg» из сборки Halfninja в /data/local/... на телефоне. При создании проекта я думаю, что исполняемый файл будет находиться в папке ../output над папкой JNI в его проекте.

Предполагая, что вы можете получить root на устройстве, вы можете затем протестировать интерфейс CLI на телефоне, получив оболочку, затем получив root с помощью «su», затем скопировав выражения cli из потоков ffmpeg/MP4/concat, таких как этот one и запустить их на телефоне с выходом в папку, к которой у вас есть доступ.

В тестовом режиме, если вы можете получить желаемый результат, используя пошаговые вызовы CLI, как показано в принятом ответе ссылки, вы можете затем вернуться к своим интерфейсам JNI, вызвав пакет «videokit» halfninja, реализуя ту же последовательность команд который вы использовали в тесте.

Добавлено примечание о множественных вызовах...

Поскольку вы будете обращаться к библиотеке ffmpeg в JNI несколько раз, вы должны знать об этой проблеме. это может повлиять на несколько вызовов ffmpeg через JNI. Если halfninja еще не урегулировал эту проблему, вам, возможно, придется изменить структуру Android.mk, чтобы реализовать библиотеку-оболочку, о которой говорилось в потоке, чтобы вы могли загружать/выгружать необходимые общие библиотеки между каждым вызовом ffmpeg через JNI. .

андроид и «кошка»

у вас должна быть симлинк в /system/bin на телефоне

lrwxr-xr-x root     shell             2012-07-09 13:02 cat -> toolbox

если нет, попробуйте установить «busybox» на телефон, чтобы вы могли имитировать сценарии на cli на телефоне.

person Robert Rowntree    schedule 23.04.2013
comment
Привет. Спасибо за попытку, но я не уверен, что вы поняли весь вопрос. У меня нет проблем с компиляцией, установкой или выполнением сборки Halfninja для ffmpeg. И я могу легко вызвать public native void run(String[] args); из VideoKit.java, например, для обрезки видео. Вопрос в следующем: какой конкретный String[] я могу передать ему, чтобы он объединял видео? - person Budius; 24.04.2013
comment
stackoverflow.com/questions/12817198/ffmpeg- 1-0-android-ndk-r8b Вы можете попробовать это, чтобы создать более новый ffmpeg на Android, содержащий «concat»… причина, по которой половина ниндзя внедрила конкретную версию ffmpeg, заключается в том, что это грязный процесс обмена diff исходные деревья для ffmpeg и ожидаем, что изменения ссылок в Android.mk будут работать. - person Robert Rowntree; 24.04.2013
comment
ты видел СФ? sourceforge.net/projects/ffmpeg4android/?source=directory - person Robert Rowntree; 30.04.2013
comment
привет Роберт, да, я видел это. Спасибо. Мне уже удалось скомпилировать его, но, как я уже сказал, я очень новичок в вопросах NDK, и мне потребуется время, чтобы обойти его и понять, как сделать оболочку JNI, особенно ту, которая преодолевает это (stackoverflow.com/questions/10649119/). Но тем временем я попробую последний ответ Стива и буду обновлять этот пост всякий раз, когда он заработает. Спасибо. - person Budius; 30.04.2013
comment
проблема dlopen/dlclose довольно хорошо известна - много сообщений. вы должны проверить вызов exit() в ffmpeg.c, просмотрев «основную» процедуру в самом низу. Причина, по которой в некоторых сообщениях говорится, что в проекте halfninja вам нужно заменить ffmpeg.c в «videokit», я думаю, отчасти из-за вызова exit() в конце. - person Robert Rowntree; 30.04.2013

В FFMPEG Fire Flower (версия 1.1) добавлен демультиплексор ffmpeg concat. Используйте огненный цветок FFmpeg или Magic, чтобы получить эту функцию. После сборки ffmpeg используйте демультиплексор. Что объясняется в этом http://ffmpeg.org/trac/ffmpeg/wiki/How%20to%20concatenate%20(join,%20merge)%20media%20files в качестве демультиплексора concat.

person Jijo Varghese    schedule 25.04.2013

Поскольку версия FFmpeg для полуниндзя не может использовать функцию конкатенации, я советую вам обновить библиотеку FFmpeg как минимум до версии 1.1.

На мой взгляд, у вас есть два варианта:

  • Попробуйте скомпилировать более новую версию FFmpeg, используя один из этих двух Руководство по компиляции FFmpeg на Android. Тогда вам, возможно, также понадобится более новая версия Android NDK. Это самое простое решение.

  • Или попробуйте реализовать более новую версию FFmpeg в библиотеках халфниндзя, что сложнее, но зато можно сохранить почти тот же интерфейс.

person Nick van Tilborg    schedule 25.04.2013

Здравствуйте, у меня есть душа. Я использую библиотеку Mp4parser

public class Mp4ParserWrapper {

    public static final String TAG = Mp4ParserWrapper.class.getSimpleName();

    public static final int FILE_BUFFER_SIZE = 1024;

    /**
     * Appends mp4 audio/video from {@code anotherFileName} to {@code mainFileName}.
     */
    public static boolean append(String mainFileName, String anotherFileName) {
        boolean rvalue = false;
        try {
            File targetFile = new File(mainFileName);
            File anotherFile = new File(anotherFileName);
            if (targetFile.exists() && targetFile.length()>0) {
                String tmpFileName = mainFileName + ".tmp";
                //mainfile=vishal0
                //another file=vishal1
                //tmpfile=vishal0.tmp

                append(mainFileName, anotherFileName, tmpFileName);
                copyFile(tmpFileName, mainFileName);
                anotherFile.delete();
                new File(tmpFileName).delete();
                rvalue = true;
            } else if ( targetFile.createNewFile() ) {
                copyFile(anotherFileName, mainFileName);
                anotherFile.delete();
                rvalue = true;
            }
        } catch (IOException e) {
            Log.e(TAG, "Append two mp4 files exception", e);
        }
        return rvalue;
    }


    public static void copyFile(final String from, final String destination)
            throws IOException {
        FileInputStream in = new FileInputStream(from);
        FileOutputStream out = new FileOutputStream(destination);
        copy(in, out);
        in.close();
        out.close();
    }

    public static void copy(FileInputStream in, FileOutputStream out) throws IOException {
        byte[] buf = new byte[FILE_BUFFER_SIZE];
        int len;
        while ((len = in.read(buf)) > 0) {
            out.write(buf, 0, len);
        }
    }

    public static void append(
            final String firstFile,
            final String secondFile,
            final String newFile) throws IOException {


        final FileInputStream fisOne = new FileInputStream(new File(secondFile));
        final FileInputStream fisTwo = new FileInputStream(new File(firstFile));
        final FileOutputStream fos = new FileOutputStream(new File(String.format(newFile)));

        append(fisOne, fisTwo, fos);

        fisOne.close();
        fisTwo.close();
        fos.close();
    }



    // FIXME remove deprecated code
    public static void append(
            final FileInputStream fisOne,
            final FileInputStream fisTwo,
            final FileOutputStream out) throws IOException {

        final Movie movieOne = MovieCreator.build(Channels.newChannel(fisOne));
        final Movie movieTwo = MovieCreator.build(Channels.newChannel(fisTwo));
        final Movie finalMovie = new Movie();

        final List<Track> movieOneTracks = movieOne.getTracks();
        final List<Track> movieTwoTracks = movieTwo.getTracks();

        for (int i = 0; i <movieOneTracks.size() || i < movieTwoTracks.size(); ++i) {
            finalMovie.addTrack(new AppendTrack(movieTwoTracks.get(i), movieOneTracks.get(i)));
        }

        final IsoFile isoFile = new DefaultMp4Builder().build(finalMovie);
        isoFile.getBox(out.getChannel());
    }

}

И вызвать с помощью:

Mp4ParserWrapper.append(firstfilename,secondfilename);
person Vishal Android developer    schedule 20.01.2014