FFmpeg: Wie kann man Videos effizient teilen?

103

Ich möchte ein großes AVI-Video in zwei kleinere aufeinanderfolgende Videos aufteilen. Ich benutze ffmpeg.

Eine Möglichkeit besteht darin, ffmpeg zweimal auszuführen:

ffmpeg -i input.avi -vcodec copy -acodec copy -ss 00:00:00 -t 00:30:00 output1.avi
ffmpeg -i input.avi -vcodec copy -acodec copy -ss 00:30:00 -t 00:30:00 output2.avi

Laut manpage von ffmpeg kann ich jedoch aus nur einer Zeile mehr als eine Ausgabedatei aus einer Eingabedatei erstellen :

ffmpeg -i input.avi -vcodec copy -acodec copy -ss 00:00:00 -t 00:30:00 output1.avi \
   -vcodec copy -acodec copy -ss 00:30:00 -t 00:30:00 output2.avi

Meine Frage ist, spart der spätere Ansatz Rechenzeit und Speicher?

Antonius
quelle
3
bei Verwendung der "-vcodec copy -acodec copy" ist es sehr schnell :))
Savas Adar
@Antony, warum zeitst du nicht beide Versionen (und schaust auf den Speichermonitor wie htop) und sagst uns, was die Antwort ist?
AlcubierreDrive
Das erste Beispiel führt dies nacheinander aus, während das zweite Beispiel Threads verwendet. Beide machen das Gleiche, es sollten keine merklichen Beschleunigungen auftreten. Aber um die Sache zu vereinfachen, könnten Sie ffmpeg Stream Segmenter Muxer verwenden: ffmpeg.org/…
Mladen B.
1
Dieses Beispiel sieht schlecht aus! In der ffmpeg-Dokumentation heißt es über die Option -ss: "Bei Verwendung als Eingabeoption (vor -i) wird in dieser Eingabedatei nach Position gesucht. Bei Verwendung als Ausgabeoption (vor einem Ausgabedateinamen) wird die Eingabe dekodiert, aber bis zum verworfen Zeitstempel erreichen Position. " Sie verwenden es an der Ausgabeposition, sodass Ihre zweite Zeile den Aufwand für das Dekodieren und Verwerfen der ersten 30 Minuten verschwendet.
Lucian Wischik
1
@LucianWischik, aber die Verwendung -ssals Eingabeoption in der zweiten Aufteilung ist möglicherweise nicht korrekt, sodass Sie möglicherweise keine saubere Aufteilung erhalten. IMO ist das Beispiel von OP korrekter.
Jiggunjer

Antworten:

82

Das ffmpeg-Wiki verweist auf diese Seite und verweist auf "So teilen Sie Videos effizient". Ich bin nicht davon überzeugt, dass diese Seite diese Frage beantwortet, also habe ich getan, wie @AlcubierreDrive vorgeschlagen hat…

echo "Two commands" 
time ffmpeg -v quiet -y -i input.ts -vcodec copy -acodec copy -ss 00:00:00 -t 00:30:00 -sn test1.mkv
time ffmpeg -v quiet -y -i input.ts -vcodec copy -acodec copy -ss 00:30:00 -t 01:00:00 -sn test2.mkv
echo "One command" 
time ffmpeg -v quiet -y -i input.ts -vcodec copy -acodec copy -ss 00:00:00 -t 00:30:00 \
  -sn test3.mkv -vcodec copy -acodec copy -ss 00:30:00 -t 01:00:00 -sn test4.mkv

Welche Ausgänge ...

Two commands
real    0m16.201s
user    0m1.830s
sys 0m1.301s

real    0m43.621s
user    0m4.943s
sys 0m2.908s

One command
real    0m59.410s
user    0m5.577s
sys 0m3.939s

Ich habe eine SD- und HD-Datei nach ein paar Läufen und ein wenig Mathe getestet.

Two commands SD 0m53.94 #2 wins  
One command  SD 0m49.63  

Two commands SD 0m55.00  
One command  SD 0m52.26 #1 wins 

Two commands SD 0m58.60 #2 wins  
One command  SD 0m58.61 

Two commands SD 0m54.60  
One command  SD 0m50.51 #1 wins 

Two commands SD 0m53.94  
One command  SD 0m49.63 #1 wins  

Two commands SD 0m55.00  
One command  SD 0m52.26 #1 wins 

Two commands SD 0m58.71  
One command  SD 0m58.61 #1 wins

Two commands SD 0m54.63  
One command  SD 0m50.51 #1 wins  

Two commands SD 1m6.67s #2 wins  
One command  SD 1m20.18  

Two commands SD 1m7.67  
One command  SD 1m6.72 #1 wins

Two commands SD 1m4.92  
One command  SD 1m2.24 #1 wins

Two commands SD 1m1.73  
One command  SD 0m59.72 #1 wins

Two commands HD 4m23.20  
One command  HD 3m40.02 #1 wins

Two commands SD 1m1.30  
One command  SD 0m59.59 #1 wins  

Two commands HD 3m47.89  
One command  HD 3m29.59 #1 wins  

Two commands SD 0m59.82  
One command  SD 0m59.41 #1 wins  

Two commands HD 3m51.18  
One command  HD 3m30.79 #1 wins  

SD-Datei = 1,35 GB DVB-Transportstrom
HD-Datei = 3,14 GB DVB-Transportstrom

Fazit

Der einzelne Befehl ist besser, wenn Sie mit HD arbeiten. Er stimmt mit den Kommentaren in den Handbüchern zur Verwendung von -ss nach der Eingabedatei überein, um eine langsame Suche durchzuführen. SD-Dateien haben einen vernachlässigbaren Unterschied.

Die Version mit zwei Befehlen sollte schneller sein, indem vor der Eingabedatei ein weiteres -ss für die 'schnelle Suche' hinzugefügt wird, gefolgt von der genaueren langsamen Suche.

user2867531
quelle
Wenn TS mehrere Programme enthält (TV-Programme, die von DVB-T aufgenommen wurden), wie kann es aufgeteilt werden? Zum Beispiel habe ich eine TS-Datei, die Fußball + Kochen + Cartoon enthält. Wie kann ich diese TS-Datei in 3 mpg-Dateien aufteilen?
Dr. Jacky
Ich habe Ihre Antwort in meiner Frage hier verwendet ( stackoverflow.com/questions/41983940/… ), aber es hat nicht funktioniert. Was denkst du, mache ich falsch?
Udev
1
Die Ergebnisdatei enthielt in meinem Fall kein Video (nur Audio). Nach einigen Experimenten fand ich eine Lösung. Es muss ein Schlüssel für "Qualität nicht ändern" wie diesen angegeben werden -q:v 0.
Oklahoma
19

Hier ist ein nützliches Skript, mit dem Sie automatisch teilen können: Ein Skript zum Teilen von Videos mit ffmpeg

#!/bin/bash
 
# Written by Alexis Bezverkhyy <[email protected]> in 2011
# This is free and unencumbered software released into the public domain.
# For more information, please refer to <http://unlicense.org/>
 
function usage {
        echo "Usage : ffsplit.sh input.file chunk-duration [output-filename-format]"
        echo -e "\t - input file may be any kind of file reconginzed by ffmpeg"
        echo -e "\t - chunk duration must be in seconds"
        echo -e "\t - output filename format must be printf-like, for example myvideo-part-%04d.avi"
        echo -e "\t - if no output filename format is given, it will be computed\
 automatically from input filename"
}
 
IN_FILE="$1"
OUT_FILE_FORMAT="$3"
typeset -i CHUNK_LEN
CHUNK_LEN="$2"
 
DURATION_HMS=$(ffmpeg -i "$IN_FILE" 2>&1 | grep Duration | cut -f 4 -d ' ')
DURATION_H=$(echo "$DURATION_HMS" | cut -d ':' -f 1)
DURATION_M=$(echo "$DURATION_HMS" | cut -d ':' -f 2)
DURATION_S=$(echo "$DURATION_HMS" | cut -d ':' -f 3 | cut -d '.' -f 1)
let "DURATION = ( DURATION_H * 60 + DURATION_M ) * 60 + DURATION_S"
 
if [ "$DURATION" = '0' ] ; then
        echo "Invalid input video"
        usage
        exit 1
fi
 
if [ "$CHUNK_LEN" = "0" ] ; then
        echo "Invalid chunk size"
        usage
        exit 2
fi
 
if [ -z "$OUT_FILE_FORMAT" ] ; then
        FILE_EXT=$(echo "$IN_FILE" | sed 's/^.*\.\([a-zA-Z0-9]\+\)$/\1/')
        FILE_NAME=$(echo "$IN_FILE" | sed 's/^\(.*\)\.[a-zA-Z0-9]\+$/\1/')
        OUT_FILE_FORMAT="${FILE_NAME}-%03d.${FILE_EXT}"
        echo "Using default output file format : $OUT_FILE_FORMAT"
fi
 
N='1'
OFFSET='0'
let 'N_FILES = DURATION / CHUNK_LEN + 1'
 
while [ "$OFFSET" -lt "$DURATION" ] ; do
        OUT_FILE=$(printf "$OUT_FILE_FORMAT" "$N")
        echo "writing $OUT_FILE ($N/$N_FILES)..."
        ffmpeg -i "$IN_FILE" -vcodec copy -acodec copy -ss "$OFFSET" -t "$CHUNK_LEN" "$OUT_FILE"
        let "N = N + 1"
        let "OFFSET = OFFSET + CHUNK_LEN"
done
Marco C.
quelle
2
Für Sie gilt der gleiche Kommentar wie für SEARAS. Das Schreiben von Batch-Dateien ist nützlich, wenn sie unbedingt benötigt werden und keine andere Option verfügbar ist, da sie nicht portierbar sind. Sie können beispielsweise nicht dasselbe Skript unter Windows ausführen. Wenn es allgemeinere / portablere Möglichkeiten gibt, sollten Batch-Skripte vermieden werden, um die für die Portierung erforderliche Zeit zu sparen. Da ffmpeg mehrere Möglichkeiten hat, um dieses Problem zu lösen, besteht die richtige Möglichkeit darin, ffmpeg allein ohne die Hilfe von Skripten zu verwenden.
Mladen B.
Schönes Skript. Hast du es geschrieben? Ist es auf GitHub? Ich möchte einige Vorschläge machen :)
Stimmen
für mp4 sind szenen beschädigt. Ersetzen Sie die Kopie besser durch: -vcodec libx264 -acodec aac
kishu
8

Verwenden Sie meiner Erfahrung nach ffmpeg nicht zum Teilen / Verbinden. MP4Box ist schneller und leichter als ffmpeg. Versuch es bitte. Wenn Sie beispielsweise eine 1400-MB-MP4-Datei in zwei Teile und 700-MB- MP4Box -splits 716800 input.mp4 Dateien aufteilen möchten, können Sie die folgende Cmdl verwenden: Zum Beispiel zum Verketten von zwei Dateien, die Sie verwenden können:

MP4Box -cat file1.mp4 -cat file2.mp4 output.mp4

Oder wenn Sie nach Zeit aufgeteilt werden müssen, verwenden Sie -splitx StartTime:EndTime:

MP4Box -add input.mp4 -splitx 0:15 -new split.mp4

Klassisch
quelle
Genau das brauchte ich! Als ich mit ffmpeg geschnitten habe, haben die Clips nicht auf Keyframes begonnen und hatten seltsame Einfrierungen an den Enden. Mit MP4Box hat -splitz den Trick gemacht!
Matt
1
Wie kann ich das Video mit Mp4Box mit mehreren Nummern zuschneiden? Zum Beispiel muss ich in Sekunden Subclips haben: 5 - 8, 21 - 30, 12 - 18, also brauche ich drei Ausgabevideodateien.
Mhndev
Und ist viel einfacher zu bedienen EndTimeals -t.
Vmassuchetto
6

http://ffmpeg.org/trac/ffmpeg/wiki/Seeking%20with%20FFmpeg kann auch für Sie nützlich sein. Außerdem hat ffmpeg einen Segment-Muxer, der möglicherweise funktioniert.

Ich vermute jedenfalls, dass das Kombinieren zu einem Befehl Zeit sparen würde.

Rogerdpack
quelle
2

Spart der spätere Ansatz Rechenzeit und Speicherplatz?

Es gibt keinen großen Unterschied zwischen den beiden von Ihnen angegebenen Beispielen. Das erste Beispiel schneidet das Video nacheinander in zwei Schritten, während das zweite Beispiel dies gleichzeitig tut (mithilfe von Threads). Es ist keine besondere Beschleunigung erkennbar. Weitere Informationen zum Erstellen mehrerer Ausgänge mit FFmpeg finden Sie hier

Darüber hinaus können Sie (in den letzten FFmpeg) den Stream-Segmenter-Muxer verwenden, der:

Ausgabestreams in eine Reihe separater Dateien von nahezu fester Dauer. Das Muster des Ausgabedateinamens kann ähnlich wie bei image2 eingestellt werden .

Mladen B.
quelle
2

Hier ist eine einfache Windows-Bat-Datei, mit der eingehende Dateien in 50 Teile aufgeteilt werden können. Jeder Teil hat eine Länge von 1 Minute. Entschuldigung für solch ein dummes Skript. Ich hoffe, es ist besser, ein dummes Windows-Skript zu haben, als es überhaupt nicht zu haben. Vielleicht hilft es jemandem. (Basierend auf "bat file for loop" von dieser Seite.)

set var=0
@echo off
:start
set lz=
if %var% EQU 50 goto end
if %var% LEQ 9 set lz=0
echo part %lz%%var%
ffmpeg -ss 00:%lz%%var%:00 -t 00:01:00 -i %1 -acodec copy -vcodec copy %2_%lz%%var%.mp4
set /a var+=1
goto start

:end
echo var has reached %var%.
exit
Alex Bor
quelle
Dies ist im Wesentlichen das erste Codefragment in der Frage (aufeinanderfolgende ffmpegBefehle), das als Schleife umgeschrieben wurde. Dies beantwortet nicht die Frage, ob dieser Ansatz oder ein einzelner Befehl "Rechenzeit und Speicher spart".
Speck
1

Hat es nicht getestet, aber das sieht vielversprechend aus:

Grundlegender Stream-Segmentierer

Es ist offensichtlich, dass AVI in Segmente gleicher Größe aufgeteilt wird, was bedeutet, dass diese Blöcke nicht an Qualität verlieren oder den Speicher erhöhen oder neu berechnet werden müssen.

Es wird auch die Codec-Kopie verwendet. Bedeutet dies, dass sehr große Streams verarbeitet werden können? Da dies mein Problem ist, möchte ich meine AVI aufteilen, damit ich einen Filter verwenden kann, um die Verzerrung zu beseitigen. Aber eine ganze Luftfahrt läuft stundenlang.

Mathias Weitz
quelle
-1

Hier ist eine perfekte Möglichkeit, das Video zu teilen. Ich habe es schon einmal gemacht und es funktioniert gut für mich.

ffmpeg -i C:\xampp\htdocs\videoCutting\movie.mp4 -ss 00:00:00 -t 00:00:05 -async 1 C:\xampp\htdocs\videoCutting\SampleVideoNew.mp4 (Für cmd). shell_exec('ffmpeg -i C:\xampp\htdocs\videoCutting\movie.mp4 -ss 00:00:00 -t 00:00:05 -async 1 C:\xampp\htdocs\videoCutting\SampleVideoNew.mp4')(für PHP).

Bitte folgen Sie diesem und ich bin sicher, dass es perfekt funktionieren wird.

Atul Upadhyay
quelle
Warum ist dies der "perfekte Weg", um das Video zu teilen? Wie die Befehlszeile in der Frage übergeben Sie -igefolgt von -ssund -t. Die Frage ist jedoch, wie mehrere Segmente effizient aus derselben Eingabedatei extrahiert werden können, während Sie nur ein einzelnes Segment extrahieren. Ich sehe nicht, wie dies die Frage beantwortet.
Speck
-2

Eine einfache Möglichkeit besteht darin, die Trimmoption mit einer auf URLs basierenden API zu verwenden .

Sobald Sie Ihr Video hochgeladen haben, setzen Sie einfach den Startversatz und den Endversatz in der URL (so_2, eo_2) wie folgt:

    https://media.publit.io/file/so_2,eo_2/tummy.mp4

Dadurch werden ab der 2. Sekunde und 2 Sekunden sofort neue Videos erstellt. Sie können Videos auf diese Weise teilen, wie Sie möchten.

ob1y2k
quelle
Die Frage ist, welcher von zwei Ansätzen zum Extrahieren mehrerer Segmente aus einer Eingabedatei mit effizienter ist ffmpeg. Wenn Sie nicht über eine sehr, sehr schnelle Internetverbindung verfügen, wird das Verarbeiten des gesamten Videos in einen Cloud-Dienst und das anschließende Herunterladen der Ergebnisse die Verarbeitungszeit erheblich verlängern. Dies beantwortet jedoch immer noch nicht die Frage, welcher Ansatz mitffmpeg effizienter ist.
Speck