jb-alvarado
Anmeldungsdatum: 28. November 2012
Beiträge: Zähle...
|
Hallo Allerseits, sorry für den Titel, irgendwie war das nicht so leicht die Problemstellung in einer Überschrift zusammenzufassen. Folgendes: mit ffprobe lasse ich mir die Key Frames und die "pkt_dts_time" eines Videoclips (key_frame,pkt_dts_time) ausgeben. Das Kommando schaut so aus:
| ffprobe -i "$inFIle" -show_frames -select_streams v -show_entries frame=key_frame -show_entries frame=pkt_dts_time -v quiet -of csv="p=0"
|
Und der Output in etwa so:
| [...]
0,657.680000
0,657.720000
0,657.760000
1,657.800000
0,657.840000
0,657.880000
0,657.920000
0,657.960000
[...]
|
Ich bräuchte jetzt eine Shell Funktion die ffprobe ausführt und wenn die "pkt_dts_time" mit einem Suchwert übereinstimmt, bzw. das erste mal größer ist, sagen wir mit 657.840000, soll das nächstgelegene "key_frame" ermittelt werden, ist das gefunden soll mir der Wert "pkt_dts_time" vor dem gefundenen key_frame ausgeben werden.
Ob das keyframe vor der "pkt_dts_time" oder nach der pkt_dts_time ermittelt wird ist egal, je nachdem was einfacher ist. Es muss nicht Framegenau sein, es ist nur wichtig, dass ich zum Schluss wirklich die "pkt_dts_time" vor dem gefundenen key_frame habe. Im Output Beispiel oben wäre der Wert den ich bräuchte: 657.760000 Gut wäre auch, wenn nicht erst das ganze Video durch gescannt wird, sondern der Treffer ffprobe stoppt. Es geht darum, dass der Wert so schnell wie möglich ermittelt wird. Bin für jeden Tipp dankbar! Grüße Jonathan
|
misterunknown
Ehemalige
Anmeldungsdatum: 28. Oktober 2009
Beiträge: 4403
Wohnort: Sachsen
|
jb-alvarado schrieb: Ich bräuchte jetzt eine Shell Funktion die ffprobe ausführt und wenn die "pkt_dts_time" mit einem Suchwert übereinstimmt, bzw. das erste mal größer ist, sagen wir mit 657.840000, soll das nächstgelegene "key_frame" ermittelt werden, ist das gefunden soll mir der Wert "pkt_dts_time" vor dem gefundenen key_frame ausgeben werden.
Du suchst wahrscheinlich grep.
Im Output Beispiel oben wäre der Wert den ich bräuchte: 657.760000
Ich würde diesen Wert so finden:
| ffprobe ... | grep -B 1 ^1
|
Grep sucht nach Zeilen, die mit einer 1 beginnen (^ = Zeilenanfang), und gibt eine Zeile davor (Before) aus. Wenn du lieber die Zeile danach hättest: After, also "-A 1". Das Suchmuster kann natürlich auch komplexer Werden, auch reguläre Ausdrücke sind möglich (-E).
Gut wäre auch, wenn nicht erst das ganze Video durch gescannt wird, sondern der Treffer ffprobe stoppt. Es geht darum, dass der Wert so schnell wie möglich ermittelt wird.
Du kannst das Kommando ausführen, warten bis eine Zeile kommt und dann manuell abbrechen.
|
jb-alvarado
(Themenstarter)
Anmeldungsdatum: 28. November 2012
Beiträge: 345
|
Ah super, wusste nicht dass grep Zeilen davor bzw. danach ausgeben kann. Denke der Hinweis reicht mir schon, danke!
|
misterunknown
Ehemalige
Anmeldungsdatum: 28. Oktober 2009
Beiträge: 4403
Wohnort: Sachsen
|
Solltest du es dann hinbekommen haben, kannst du das Thema ja auf gelöst setzen ☺
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
So ganz verstanden habe ich es noch nicht, was Du wie aus Deinem Datenstrom heraus ziehen willst ...
Grundsätzlich willst Du ja einen Zahlenwert an die Shell übergeben; dafür brauchst Du auf jeden Fall eine Command Substitution. Dann suchst Du einen "kleiner gleich"- Vergleich - dazu wird Dir grep wenig helfen (das erkennt nur Muster !), sondern Du brauchst etwas das numerisch vergleichen kann (→ Fließkommazahlen ?). Dafür wäre awk der naheliegendste Kandidat. Du willst so schnell wie möglich abbrechen. Das geschieht automatisch, wenn Du z.B. awk mit ffprobe per Pipe zusammen in einer Command Substitution hast. Wenn dann awk abbricht, wird ffprobe mit abgebrochen.
... soweit erstmal als Grobskizze. LG, track
|
misterunknown
Ehemalige
Anmeldungsdatum: 28. Oktober 2009
Beiträge: 4403
Wohnort: Sachsen
|
track schrieb: Grundsätzlich willst Du ja einen Zahlenwert an die Shell übergeben; dafür brauchst Du auf jeden Fall eine Command Substitution.
Nö, eine Pipe reicht dafür aus. Richtig ist, dass awk im Gegensatz zu grep Vergleiche mit Zahlen machen kann. Die Frage ist, ob es reicht per Muster zu suchen (grep), oder ob man einen mathematischen Vergleich anstellen muss (awk). Aus Performancegründen würde ich grep awk vorziehen, sofern das möglich ist.
|
jb-alvarado
(Themenstarter)
Anmeldungsdatum: 28. November 2012
Beiträge: 345
|
Ja du hast recht track. War etwas zu schnell ☺. Mit dem grep Befehl bekomme ich in etwa so etwas raus: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 | 0,6.000000
1,6.040000
--
0,7.000000
1,7.040000
--
0,8.000000
1,8.040000
--
0,9.000000
1,9.040000
--
0,10.000000
1,10.040000
--
0,11.000000
1,11.040000
--
0,12.000000
1,12.040000
|
Ich dachte ich könnte beim grep statt ^1 die Sekunde eingeben, nach der ich suche, aber das ist nicht zuverlässig, weil es unter Umständen sein kann, dass gerade diese Sekunde kein Key Frame hat. Also muss wirklich etwas her was größer gleich vergleicht. Habe jetzt eine Kombi aus awk und grep was wie folgend ausschaut: | ffprobe [...] | awk -F',' '{ if ($2 > $SuchzeitMin && $2 < $SuchzeitMax) print $1,$2 }' | grep -B 1 ^1 | head -n 1 | cut -d " " -f2
|
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Statt mir irgendwelchen Code als Puzzel-Aufgabe zu geben, solltest Du vielleicht besser nochmal genau sagen, wie Deine Filterkriterien aussehen ... 😬 Also: was ist überhaupt die "Frame-Zeit" ? - nur die Zahl hinter dem Komma ? Und was bedeutet dann die Zahl vorne ? Wie erkennt man das nächstgelegene Key-frame ? - was heißt "nächstgelegen" ? - soll der Absolutwert der Abweichung möglichst klein sein, oder suchst Du nur positive Zeiten ...? Beschreib die ganze Aufgabenstellung doch bitte mal in "Prosa", für jemanden, der ffprobe nicht kennt. track
|
jb-alvarado
(Themenstarter)
Anmeldungsdatum: 28. November 2012
Beiträge: 345
|
Ok, ich versuche es noch mal ☺. ffprobe spuckt mit dem Kommando aus dem ersten Beitrag für jedes Videoframe ein Zahlenpaar aus, der Delimiter ist das Komma. Die erste Zahl gibt an ob es sich um ein Keyframe handelt (1), wenn es kein Keyframe ist steht dort 0 . Die zweite Zahl gibt die Zeit des Frames aus, an welcher Stelle ffprobe im Video gerade ist, der Wert ist hier in Sekunden. Ich habe jetzt einen Prüfwert, sagen wir 657.3. Nun möchte ich diesen Prüfwert mit dem Output von ffprobe abgleichen. Und zwar soll der Wert mit der zweiten Stelle des Zahlenpaares verglichen werden und wenn die Zahl stimmt, bzw. das erste mal größer ist, soll in einem zweiten Schritt geprüft werden wann ab diesem Zeitpunkt (das letzte mal vor dem Treffer geht auch) ein Keyframe ist, also eine 1 im Zahlenpaar an erster Stelle. Ist das Keyframe gefunden brauche ich nun die Zeit des Frames davor. | 0,657.760000 # <-- dieses Zahlenpaar brauche ich, bzw. die zweite Einheit davon.
1,657.800000
0,657.840000
0,657.880000
0,657.920000
|
Ist das verständlicher?
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Ja, ok. Verstehe ich das richtig, dass Du den Zeitstempel des letzten Frames vor dem Keyframe haben willst ? Sowas ist mit awk jedenfalls recht bequem in einem Rutsch zu erledigen. Ich versuche es mal, so wie ich es jetzt verstanden habe. Hier mal zur besseren Übersicht als Skript geschrieben: | #!/usr/bin/awk -f
BEGIN { FS= "," }
{ if($1 == 1) t_vor_key= vor_t;
if($2 >= zielzeit) { # die Zielzeit kann man im Einzeiler als Shellvariable übergeben
print t_vor_key;
exit } # ... und sofort beenden, wir wollen ja Zeit sparen
vor_t= $2 } # vorigen Zeitstempel merken
|
Das wäre jetzt die Variante für den letzten Keyframe vor der Zielzeit. Bei dem 1. Keyframe danach muss man die Logik ein bisschen umdrehen, das ist alles. Oder Du bestimmst beide, und guckst, welcher näher dran liegt ... alles machbar ! Mal als Einzeiler getestet: track@lucid:~$ zielzeit=657.9
track@lucid:~$ echo '0,657.760000
1,657.800000
0,657.840000
0,657.880000
0,657.920000' | awk -F, "{ if(\$1 == 1) tvk= vt; if(\$2 >= $zielzeit) { print tvk; exit } vt= \$2 }"
657.760000 Die "$" für die awk- Variablen müssen hier escaped werden, damit die Shell die Finger davon lässt. Praktisch stopfst Du das natürlich zusammen mit ffprobe in eine Command Substitution, dann bist Du fertig: framezeit=$( ffprobe -i "$inFIle" -show_frames -select_streams v -show_entries frame=key_frame -show_entries frame=pkt_dts_time -v quiet -of csv="p=0" | awk -F, "{ if(\$1 == 1) tvk= vt; if(\$2 >= $zielzeit) { print tvk; exit } vt= \$2 }" ) LG, track
|
jb-alvarado
(Themenstarter)
Anmeldungsdatum: 28. November 2012
Beiträge: 345
|
Hallo track,
ja das ist richtig, ich brauche das letzte Frame vor dem Keyframe. Dein awk Code lief im ersten Test super! Leider hat anscheinend ffprobe nicht abgebrochen nach dem Match, aber das ist verkraftbar. Danke noch mal!
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Na ja, normalerweise sollte bei einer Pipe das Programm abbrechen, wenn die Pipe abgebaut wird ... Mal gucken, vielleicht liegt es ja am Buffering. Das kann man bei awk abschalten: Füg mal bitte direkt vor dem exit ein fflush(""); ein. (für ffprobe musst Du es mal selber in man ffprobe nachgucken: Sichwort "Buffer") Sonst ginge es auch ganz brutal, indem Du von awk aus mit einem System-Befehl den ffprobe killst, mit einem system("killall ffprobe"); direkt vor dem exit . Das geht mit awk auch. 😀 LG, track
|
jb-alvarado
(Themenstarter)
Anmeldungsdatum: 28. November 2012
Beiträge: 345
|
Danke noch mal, werde morgen mal die Tipps nacheinander versuchen ☺. Edit: auf die brutale Tour geht es.
|