ffmpeg: Wie entscheidet ffmpeg, welche Frames ausgewählt werden sollen, wenn der fps-Wert angegeben wird?

1545
diggy

Ich verwende ffmpeg, um mit diesem Befehl 3 Bilder pro Sekunde zu extrahieren

ffmpeg -i input.flv -f image2 -vf fps=fps=3 out%d.png 

Ich frage mich, ob ich den fps-Wert einstelle. Wie wählt ffmpeg dann 3 Frames in einer Sekunde aus. Ist es zufällig oder dauert es die ersten 3 Frames in dieser Sekunde? Irgendeine Hilfe?

1
Ohne zu viel Wissen darüber, wie es funktioniert, würden sie wahrscheinlich gleichmäßig verteilt werden. Wenn Sie also 30 Frames haben und 3 wollen, würden Sie 1,15 und 30 brauchen. Die ersten 3 zu machen, macht keinen Sinn ein Video erstellen. Adam vor 10 Jahren 0
Ja. Das ist was ich dachte. Aber da ich diese Frames für meine Arbeit verwenden werde, muss ich sichergehen, ob der Frame in einer Sekunde gleichmäßig extrahiert wird oder was genau die Kriterien sind. diggy vor 10 Jahren 0
Warum nicht einfach alle Bilder in Bilder umwandeln, können Sie bestimmte auswählen und dann die Bilder wieder in ein Video umwandeln. [So geht's] (http://pr0gr4mm3r.com/linux/convert-video-to-images-and-back-using-ffmpeg/) Adam vor 10 Jahren 0
Experimentieren Sie, erzeugen Sie einige PNGs aus beiden FPS und sehen Sie, wo sie ausgerichtet sind. Oder schauen Sie in den Code, um herauszufinden, wie diese Entscheidungen getroffen werden. Wie bereits erwähnt, gibt es eine programmatische Methode für die Auswahl der PNGs, so dass es nicht zufällig sein wird. dstob vor 10 Jahren 1

1 Antwort auf die Frage

3
slhck

Dies geschieht durch die Neuskalierung von Zeitstempelwerten von der Eingabezeitbasis (dh FPS als Bruchwert, z. B. 24 fps würde 1/24), zur Ausgabezeitbasis.

Zuerst wird die Zeitbasis basierend auf der angeforderten FPS festgelegt:

link->time_base = av_inv_q(s->framerate); 

Beim Filtern wird die Anzahl der Ausgangsframes basierend auf der Anzahl der Eingangsframes im Puffer berechnet, wobei diese Anzahl zwischen den beiden Zeitbasen skaliert wird, also im Grunde Frames × Input / Output . Beachten Sie, dass es sich buf->pts - s->first_ptsoffensichtlich um eine Anzahl von Frames handelt, nicht um einen tatsächlichen Unterschied in der PTS-Zeit.

/* number of output frames */ delta = av_rescale_q_rnd(buf->pts - s->first_pts, inlink->time_base, outlink->time_base, s->rounding) - s->frames_out ; 

Wenn die Eingabezeitbasis beispielsweise 0,042 (24 fps) und der Ausgang 0,33 (3 fps) beträgt und Sie 12 Eingabefelder im Puffer haben, erhalten Sie 12 × 0,042 / 0,33- Frames, die auf die nächsten gerundet werden Integer 2 - also sollen zwei Frames erzeugt werden. Wenn Sie 24 Frames haben, erhalten Sie natürlich drei Frames. Für 35 Frames im Eingangspuffer erhalten Sie vier Output-Frames.

Wenn dieses Delta kleiner als 1 ist, können die Frames im Puffer gelöscht werden, da in diesem Zeitraum kein Frame benötigt wird. Wenn andererseits das Delta größer als eins ist, muss die Anzahl der Frames für den Eingangspuffer ausgegeben werden.

Bei neuen Frames wird der PTS-Wert basierend auf den Zeitbasen der Eingabe und Ausgabe skaliert:

buf_out->pts = av_rescale_q(s->first_pts, inlink->time_base, outlink->time_base) + s->frames_out; 

In der Praxis bedeutet dies, dass Sie sich das PTS Ihres Eingangsvideos ansehen müssen, wie viele Frames pro Sekunde Ihre Ausgabe haben kann, und diese dann gleichmäßig verteilen, indem Sie Frames je nach Bedarf löschen. Wenn Sie extrem präzise sein möchten, würde ich empfehlen, den Quellcode mit ein paar Testvideos zu debuggen.

Ich fürchte, ich kann keine praktischere Lösung finden als die Antwort, die ich vor kurzem hier gepostet habe und in der ich erkläre, wie der PTS jedes Frames in einem Video gezeigt wird, dessen Framerate geändert wurde:

ffmpeg -i input.mp4 -t 10 -filter:v "fps=fps=25, showinfo" -f null - 2>&1 grep pts_time | awk '' | cut -d: -f2 

Diese Zeitstempel gehören zu jedem Ausgangsrahmen und seiner entsprechenden PTS-Eingangszeit.