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 -1
Parameter 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 900
scheint 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 13494
scheint 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_time
sollte 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_list
war 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 strftime
ein %s
Format 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 %d
Formatierung 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 -re
Flags dieses Problem durch Verlangsamung der Verarbeitung umgehen würde, aber ich möchte eigentlich eine beschleunigte Verarbeitung. Daher habe ich das nicht ausprobiert.