Конкатенировать файлы mp4 в Android с помощью halfninja ffmpeg
Мне удалось скомпилировать скрипты halfninja ffmpeg для Android NDK, используя версию NDK r5c. (К сожалению, любая попытка скомпилировать с более ранним NDK вызвала некоторую ошибку), также я не очень хорошо разбираюсь во всем процессе NDK, поэтому для меня это немного ударит-n-miss.
Его скрипты компилируют ffmpeg версию N-30996-gf925b24 (конкретный фиксатор, который он сделал для скриптов)
Переход к моему фактическому приложению.
Мне удается обрезать видео без проблем, теперь мне нужно объединить/объединить их, но любой attemp при использовании любых и нескольких комбинаций команд, найденных на этих трех ссылках (link1, link2, 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;
}
Ответы
Ответ 1
Ответ, предоставленный 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 * без * повторного кодирования
Ответ 2
эта последовательность будет кота mp4 в CLI. его на странице ffmpeg faq при конкатенации...
$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
Я посмотрел на halfninja "Android.mk"... и для тестирования вы должны использовать adb для запуска исполняемого файла "ffmpeg" из сборки halfninja в /data/local/... на телефоне. При создании проекта я думаю, что исполняемый файл будет находиться в папке.. /output, над папкой JNI в его проекте.
Предполагая, что вы можете получить root на устройстве, вы можете выполнить тестирование на интерфейсе CLI на телефоне, получив оболочку, затем получив root, используя 'su', а затем скопируйте выражения cli из ffmpeg/MP4/concat threads, таких как этот один и запустив их на телефоне с выходами в папку, в которой у вас есть доступ.
В тестовом режиме, если вы можете получить желаемый результат, используя шаг за раз, когда CLI-вызовы, как показано в ответе на связь, вы можете вернуться к интерфейсам JNI, вызвав пакет halfninja 'videokit', реализуя тот же последовательность команд, которые вы использовали в тесте.
Добавлена заметка о нескольких вызовах...
Поскольку вы будете входить в ffmpeg lib в JNI несколько раз, вы должны знать об этой проблеме которая может повлиять на несколько вызовов в ffmpeg через JNI. Если halfninja еще не выполнил эту проблему, вам, возможно, придется изменить структуру Android.mk, чтобы реализовать библиотеку обертки, о которой говорилось в потоке, чтобы вы могли загружать/выгружать необходимые общие библиотеки между каждым вызовом ffmpeg через JNI,
android и 'cat'
у вас должна быть символическая ссылка в /system/bin на телефоне
lrwxr-xr-x root shell 2012-07-09 13:02 cat -> toolbox
Если нет, попробуйте установить "busybox" на телефоне, чтобы вы могли имитировать скрипты на кли.
Ответ 3
ffmpeg concat demuxer добавлен в FFMPEG Fire Flower (версия 1.1). Используйте FFmpeg fire flower или Magic, чтобы получить эту функцию. Когда вы создадите ffmpeg, используйте demuxer. Что объясняется в этом http://ffmpeg.org/trac/ffmpeg/wiki/How%20to%20concatenate%20(join,%20merge)%20media%20files
сайт как concat demuxer.
Ответ 4
Так как версия halffinja FFmpeg не может использовать функциональность concatenate, я советую вам обновить библиотеку FFmpeg, по крайней мере, до версии 1.1.
По-моему, у вас есть два варианта:
-
Попробуйте скомпилировать более новую версию FFmpeg, используя один из этих Компиляция FFmpeg на Android. Тогда вам также может понадобиться более новая версия Android NDK. Это самое простое решение.
-
Или попробуйте реализовать более новую версию FFmpeg в библиотеках halfninja, что сложнее, но тогда вы можете поддерживать почти тот же интерфейс.
Ответ 5
Привет, у меня есть эта душа. Я использую библиотеку 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);