ffmpeg-Segment nach Videozeit statt nach Wandzeit

ffmpeg-Segment nach Videozeit statt nach Wandzeit

Ich habe ein System, das Videos auf Festplatte aufzeichnet, und manchmal tritt bei diesem System ein Fehler auf. Ich versuche, das Aufnahmesystem im Labor nachzubauen, ohne die eigentliche Kamera (sie ist teuer und es gibt keine Ersatzteile), um das Nutzungsmuster zu reproduzieren, das den Fehler verursacht.

Ich habe Probleme, ffmpeg zu zähmen.

Hintergrund:

Das Video wird in einem Thread kontinuierlich von einer rtsp://-URL aufgenommen, die von der angeschlossenen Kamera mit diesem Befehl bereitgestellt wird:

ffmpeg -i rtsp://192.168.0.10/h264 -c copy -map 0 -f segment -segment_time 900 -segment_format mp4 -segment_atclocktime 1 -strftime 1 /tmp/capture-%s.mp4

Dies funktioniert und erzeugt wie erwartet Videodateien mit einer Länge von 15 Minuten.

Problem:

Im Labor habe ich weder die Kamera noch den rtsp://-Stream. Ich habe stattdessen eine der aufgenommenen MP4s vom realen System kopiert und verwende diese stattdessen als Eingabe für ffmpeg. So etwas wie:

ffmpeg -stream_loop -1 -i capture-1469547000.mp4 -c copy -map 0 -f segment **-{NEED PARAM}** -segment_format mp4 -strftime 1 /tmp/captest-%s.mp4

Der -stream_loop -1Parameter tut, was erwartet wird: Er liest aus der Eingabedatei (die 15 Minuten lang ist) und erzeugt einen unendlichen Ausgabestream. Dies ist eine vernünftige Annäherung an das Lesen aus dem rtsp://-Stream.

Was ich nicht herausfinden kann, ist, welche Parameter ich verwenden muss, damit dieses Laborsystem das Video in 15-Minuten-Blöcke segmentiert, genau wie das echte System. Was ich erwarte, ist eine Folge von Ausgabedateien, die jeweils ungefähr so ​​groß sind wie die Eingabedatei.

Versuch Nr. 1

Die Verwendung -segment_time 900scheint entweder a) den Echtzeitwert von 15 Minuten verwenden zu wollen oder b) ignoriert zu werden. Da das Kopieren von einer vorhandenen MP4-Datei viel schneller ist als das Kopieren vom rtsp://-Stream, besteht die resultierende Aufnahmedatei aus vielen, vielen Kopien des Originals.

Versuch Nr. 2

Ich habe diesen Befehl verwendet

ffprobe -v error -count_frames -select_streams v:0 -show_entries stream=nb_read_frames -of default=nokey=1:noprint_wrappers=1 capture-1469547000.mp4

um festzustellen, dass die Eingabedatei 13494 Frames hat.

Die Verwendung -segment_frames 13494scheint ignoriert zu werden und die Ausgabe wird überhaupt nicht segmentiert.

Versuch Nr. 3

Ich habe einen Großteil der ffmpeg-Dokumentation gelesen und entweder fehlt mir, was ich brauche, oder es existiert nicht.

Bei Verwendung -ss *position* -t *duration*erfolgt keine kontinuierliche Aufzeichnung und Segmentierung der Ausgabe.

Bitte um Hilfe

Welche Parameter muss ich verwenden, damit die Segmentierung a) funktioniert und b) eine Videolänge von 15 Minuten erreicht?

Mögliche Komplikation

Die Zeitstempel (DTS?) im Beispiel-MP4 sind nicht „gut“, da dieser Fehler kontinuierlich auftritt:

[Segment @ 0x2abc7c0] Nicht monotones DTS im Ausgabestream 0:0; vorher: 80990160, aktuell: -74730276972; Änderung auf 80990161. Dies kann zu falschen Zeitstempeln in der Ausgabedatei führen.  
DTS 191648787, next:-830336344130 st:0 ungültiges Löschen  
PTS 191648787, nächster: -830336344130 ungültiger Drop-St:0

Da ich die resultierenden Videodateien jedoch nicht unbedingt abspielen möchte oder sie intakt halten müssen, ignoriere ich dies, sofern es nicht die Segmentierung beeinträchtigt, die ich neu erstellen muss.

Weitere Informationen

ffmpeg-Version:

\# /usr/share/local/bin/ffmpeg -version  
ffmpeg Version N-79587-g9f9c833 Copyright (c) 2000-2016 die FFmpeg-Entwickler  
erstellt mit gcc 4.8 (Ubuntu/Linaro 4.8.2-16ubuntu4)  
Konfiguration: --prefix=/home/t/dev/j/third-party/ffmpeg/../build --cross-prefix=/usr/bin/arm-linux-gnueabihf- --cpu=armv7-a --disable-shared --enable-static --enable-gpl --enable-pthreads --enable-nonfree --enable-libx264 --enable-filters --extra-libs=-static --extra-cflags=--static --enable-cross-compile --target-os=linux --disable-inline-asm --arch=armv7 --disable-debug --disable-altivec --disable-sse --disable-armv6 --disable-armv6t2 --disable-mmx --disable-neon --disable-amd3dnow --disable-thumb --extra-ldflags=-L/home/t/dev/j/Drittanbieter/ffmpeg/../build/lib --extra-cflags=-I/home/t/dev/j/Drittanbieter/ffmpeg/../build/include --extra-ldflags=-L/home/t/dev/j/Drittanbieter/ffmpeg/libavcodec --extra-ldflags=-L/home/t/dev/j/Drittanbieter/ffmpeg/libavdevice --extra-ldflags=-L/home/t/dev/j/Drittanbieter/ffmpeg/libavfilter --extra-ldflags=-L/home/t/dev/j/Drittanbieter/ffmpeg/libavformat --extra-ldflags=-L/home/t/dev/j/Drittanbieter/ffmpeg/libavresample --extra-ldflags=-L/home/t/dev/j/third-party/ffmpeg/libavutil --extra-ldflags=-L/home/t/dev/j/third-party/ffmpeg/libswscale --extra-ldflags=-lx264 --extra-ldflags=-lm --extra-ldflags=-ldl --extra-cflags='-fpic -mthumb'  
libavutil 55.22.101 / 55.22.101  
libavcodec 57.38.100 / 57.38.100  
libavformat 57.34.103 / 57.34.103  
libavdevice 57.0.101 / 57.0.101  
libavfilter 6.44.100 / 6.44.100  
libswscale 4.1.100 / 4.1.100  
libswresample 2.0.101 / 2.0.101  
libpostproc 54.0.100 / 54.0.100

Antwort1

segment_timesollte funktionieren. Es bezieht sich auf die Segmentdauer, nicht auf die Wanduhr.

Die Platzierung der Keyframes kann störend sein. Versuchen Sie daher,

ffmpeg -fflags +genpts -i capture-1469547000.mp4 -c copy -map 0 -f segment -segment_time 900 -segment_format mp4 -break_non_keyframes 1 -strftime 1 /tmp/capture-%s.mp4

Ich habe die Option stream_loop entfernt, da es derzeit einen Fehler bei der Zeitstempelgenerierung im Zusammenhang mit ihrer Verwendung gibt. Das könnte hier ebenfalls störend sein.

Wenn Sie zum Arbeiten einen wirklich langen Stream benötigen, verwenden Sie den Concat-Demuxer.

Erstellen einer Textdatei

file 'capture-1469547000.mp4'
file 'capture-1469547000.mp4'
file 'capture-1469547000.mp4'
file 'capture-1469547000.mp4'
file 'capture-1469547000.mp4'
file 'capture-1469547000.mp4'
file 'capture-1469547000.mp4'
file 'capture-1469547000.mp4'

Und dann verwenden

ffmpeg -f concat -i list.txt -c copy ...

Antwort2

Ich habe eine funktionierende Lösung.

Die Grundursache

Die von mir gespeicherte Beispielaufnahmedatei erwies sich für die von mir gewünschten Zwecke (ein unendlicher Eingabestrom) als nicht „gut“, obwohl es sich ansonsten um eine gute Videodatei handelt (sie lässt sich gut abspielen, ist aber nicht suchbar). Das Problem scheint mit den Zeitstempeln und möglicherweise auch mit einem oder mehreren Fehlern im Segment-Multiplexer zusammenzuhängen.

Die Lösung

Ich rannte

ffmpeg -i capture-1469547000.mp4 -c copy captemp.mp4

Wenn ich sie stattdessen verwende captemp.mp4, erhalte ich entweder mit stream_loop oder dem Concat-Muxer einen guten Stream.

Ich bin nicht sicher, was der Unterschied zwischen capture-1469547000.mp4 und captemp.mp4 ist; AtomicParsley zeigt, dass captemp.mp4 im „elst“-Atom 12 Bytes kürzer ist.

Ein erneuter Blick auf mein ursprüngliches Setup und das Hinzufügen von Elementen segment_listwar aufschlussreich: Die Segmente wurden korrekt generiert, aber sehr, sehr schnell. Sie wurden einfach an die vorhandene Segmentdatei angehängt, anstatt eine neue zu erstellen. Das ist teilweise die Schuld von ...

Strftime potenzieller Fehler

Ich habe strftimeein %sFormat verwendet. Es stellte sich heraus, dass strftime die Uhrzeit des Hostcomputers verwendete und nicht die Zeit aus dem Videosegment. Dies gilt sogar im „funktionierenden“ Fall. Ich bin stattdessen auf die %dFormatierung des Segmentmultiplexers umgestiegen.

Dies ist wahrscheinlich ein Fehler und der Grund, warum im nicht funktionierenden Fall die Segmente aneinander angehängt wurden.

Ich bin ziemlich sicher, dass die Verwendung des -reFlags dieses Problem durch Verlangsamung der Verarbeitung umgehen würde, aber ich möchte eigentlich eine beschleunigte Verarbeitung. Daher habe ich das nicht ausprobiert.

verwandte Informationen