Wie extrahiere ich die Zeitdauer aus der ffmpeg-Ausgabe?

77

Um viele Informationen über eine Mediendatei zu erhalten, kann man dies tun

ffmpeg -i <filename>

Dort werden viele Zeilen ausgegeben, insbesondere eine

Duration: 00:08:07.98, start: 0.000000, bitrate: 2080 kb/s

Ich möchte nur ausgeben 00:08:07.98, also versuche ich es

ffmpeg -i file.mp4 | grep Duration| sed 's/Duration: \(.*\), start/\1/g'

Aber es druckt alles und nicht nur die Länge.

Auch ffmpeg -i file.mp4 | grep Durationgibt alles.

Wie bekomme ich nur die Dauer?

Louise
quelle
1
IMHO MediaInfo würde Ihnen sicherlich eine viel einfachere Analyse der Ausgabe bieten.
SirDarius

Antworten:

59

ffmpeg schreibt diese Informationen stderrnicht an stdout. Versuche dies:

ffmpeg -i file.mp4 2>&1 | grep Duration | sed 's/Duration: \(.*\), start/\1/g'

Beachten Sie die Umleitung stderrzu stdout:2>&1

BEARBEITEN:

Ihre sedAussage funktioniert auch nicht. Versuche dies:

ffmpeg -i file.mp4 2>&1 | grep Duration | awk '{print $2}' | tr -d ,
Louis Marascio
quelle
3
Grep ist unnötig, reicht sed -n 's/Duration: \(.*\), start/\1/gp'aus.
Potong
11
Eigentlich sedist unnötig:ffmpeg -i file.mp4 2>&1 | grep -o -P "(?<=Duration: ).*?(?=,)"
25.
1
Was ist der Kontext dafür, wenn ich die Dauer als Variable speichern möchte, die im selben PHP-Skript verwendet werden soll?
schwindelerregende
Wie mache ich dasselbe in Python?
Prakhar Mohan Srivastava
18
Die Verwendung von ffprobe, wie in anderen Antworten angegeben, scheint ein sauberer und stressfreier Ansatz zu sein :)
Pirkka Esko
161

Sie können verwenden ffprobe:

ffprobe -i <file> -show_entries format=duration -v quiet -of csv="p=0"

Die Dauer wird in Sekunden ausgegeben, z. B.:

154.12

Durch Hinzufügen der -sexagesimalOption wird die Dauer in Stunden: Minuten: Sekunden ausgegeben. Mikrosekunden :

00:02:34.12
Ivan Neeson
quelle
1
Für mein ffmpeg-0.6.5-1.el6.rf.x86_64 lautet das Format: ffprobe <Datei> -show_format 2> & 1 | sed -n 's / duration = // p'
Sunry
2
Dies ist der richtige Weg. ffmpeg -i wollte nach dem Drucken der Daten immer eine neue Datei transkodieren. Viel sauberere Lösung hier.
Pirkka Esko
Sollte die akzeptierte Antwort sein, obwohl das Ausgabeformat (Sekunden) nicht genau das ist, wonach gefragt wurde.
Bovender
3
@bovender Antwort aktualisiert mit Option zur Ausgabe des gewünschten Formats.
Llogan
1
@ LordNeckbeard Jetzt sollte es wirklich die akzeptierte Antwort sein!
Bovender
13

Nach meiner Erfahrung bieten viele Tools die gewünschten Daten in einer Art Tabelle / geordneter Struktur an und bieten auch Parameter zum Sammeln bestimmter Teile dieser Daten. Dies gilt beispielsweise auch für smartctl, nvidia-smi und ffmpeg / ffprobe. Einfach gesagt - oft ist es nicht erforderlich, Daten umzuleiten oder Unterschalen für eine solche Aufgabe zu öffnen.

Infolgedessen würde ich das richtige Werkzeug für den Job verwenden - in diesem Fall würde ffprobe den Rohdauerwert in Sekunden zurückgeben, danach könnte man das gewünschte Zeitformat selbst erstellen:

$ ffmpeg --version
ffmpeg version 2.2.3 ...

Der Befehl kann je nach verwendeter Version variieren.

#!/usr/bin/env bash
input_file="/path/to/media/file"

# Get raw duration value
ffprobe -v quiet -print_format compact=print_section=0:nokey=1:escape=csv -show_entries format=duration "$input_file"

Eine Erklärung:

"-v quiet": Geben Sie nichts anderes als den gewünschten Rohdatenwert aus

"-print_format": Verwenden Sie ein bestimmtes Format, um die Daten auszudrucken

"compact =": Verwenden Sie ein kompaktes Ausgabeformat

"print_section = 0": Den Abschnittsnamen nicht drucken

": nokey = 1": Drucken Sie nicht den Schlüssel des Schlüssel: Wert-Paares

": Escape = CSV": Escape den Wert

"-show_entries format = duration": Ruft Einträge eines Feldes mit dem Namen dauer in einem Abschnitt mit dem Namen format ab

Referenz: ffprobe Manpages

Saucier
quelle
4

Ich empfehle die Verwendung des JSON-Formats, es ist einfacher zum Parsen

ffprobe -i your-input-file.mp4 -v quiet -print_format json -show_format -show_streams -hide_banner

{
    "streams": [
        {
            "index": 0,
            "codec_name": "aac",
            "codec_long_name": "AAC (Advanced Audio Coding)",
            "profile": "HE-AACv2",
            "codec_type": "audio",
            "codec_time_base": "1/44100",
            "codec_tag_string": "[0][0][0][0]",
            "codec_tag": "0x0000",
            "sample_fmt": "fltp",
            "sample_rate": "44100",
            "channels": 2,
            "channel_layout": "stereo",
            "bits_per_sample": 0,
            "r_frame_rate": "0/0",
            "avg_frame_rate": "0/0",
            "time_base": "1/28224000",
            "duration_ts": 305349201,
            "duration": "10.818778",
            "bit_rate": "27734",
            "disposition": {
                "default": 0,
                "dub": 0,
                "original": 0,
                "comment": 0,
                "lyrics": 0,
                "karaoke": 0,
                "forced": 0,
                "hearing_impaired": 0,
                "visual_impaired": 0,
                "clean_effects": 0,
                "attached_pic": 0
            }
        }
    ],
    "format": {
        "filename": "your-input-file.mp4",
        "nb_streams": 1,
        "nb_programs": 0,
        "format_name": "aac",
        "format_long_name": "raw ADTS AAC (Advanced Audio Coding)",
        "duration": "10.818778",
        "size": "37506",
        "bit_rate": "27734",
        "probe_score": 51
    }
}

Sie finden die Dauerinformationen im Formatabschnitt, der sowohl für Video als auch für Audio funktioniert

vivisidea
quelle
Vielen Dank! Genau das brauchte ich!
Matt W
4

Wenn Sie die Länge (und möglicherweise alle anderen Metadaten) mit ffmpeg mithilfe eines Python-Skripts aus Ihrer Mediendatei abrufen möchten, können Sie Folgendes versuchen:

import subprocess
import json

input_file  = "< path to your input file here >"

metadata = subprocess.check_output(f"ffprobe -i {input_file} -v quiet -print_format json -show_format -hide_banner".split(" "))

metadata = json.loads(metadata)
print(f"Length of file is: {float(metadata['format']['duration'])}")
print(metadata)

Ausgabe:

Length of file is: 7579.977143

{
  "streams": [
    {
      "index": 0,
      "codec_name": "mp3",
      "codec_long_name": "MP3 (MPEG audio layer 3)",
      "codec_type": "audio",
      "codec_time_base": "1/44100",
      "codec_tag_string": "[0][0][0][0]",
      "codec_tag": "0x0000",
      "sample_fmt": "fltp",
      "sample_rate": "44100",
      "channels": 2,
      "channel_layout": "stereo",
      "bits_per_sample": 0,
      "r_frame_rate": "0/0",
      "avg_frame_rate": "0/0",
      "time_base": "1/14112000",
      "start_pts": 353600,
      "start_time": "0.025057",
      "duration_ts": 106968637440,
      "duration": "7579.977143",
      "bit_rate": "320000",
      ...
      ...
petezurich
quelle
Dieser Code funktioniert nicht: Traceback (most recent call last): File "ffprobe.py", line 9, in <module> print("Length of file is: {}".format(float(length["format"]["duration"]))) NameError: name 'length' is not defined Dies sollte den Job machen: import subprocess import json input_file = "out.mp4" metadata = subprocess.check_output(f"ffprobe -i {input_file} -v quiet -print_format json -show_format -hide_banner".split(" ")) metadata = json.loads(metadata) print("Length of file is: {}".format(float(metadata["format"]["duration"]))) print(metadata)
Rabindranath Andujar
@ RabindranathAndujar Ich habe noch einmal überprüft. Du hast recht. Der Code funktioniert, aber die Zeile für den Ausdruck enthielt einen Fehler. Ich habe den Code korrigiert und jetzt läuft er einwandfrei. Vielen Dank für den Hinweis.
Petezurich
Dieses Skript
schlägt
4

Bei einem Anforderungsparameter ist es einfacher, mediainfo und seine Ausgabeformatierung wie folgt zu verwenden (für die Dauer; Antwort in Millisekunden).

mediainfo --Output="General;%Duration%" ~/work/files/testfiles/+h263_aac.avi 

Ausgänge

24840
gemelen
quelle
2
Dies sollte 'mediainfo --Inform = "General;% Duration%" ~ / work / files / testfiles / + h263_aac.avi' sein
Pogrindis
Beide Formen funktionieren identisch in mediainfo v18.05 (und scheinen mit früheren Versionen zu sein).
Gemelen
1

Für diejenigen, die dieselben Berechnungen ohne zusätzliche Software in Windows ausführen möchten, ist hier das Skript für das Befehlszeilenskript:

set input=video.ts

ffmpeg -i "%input%" 2> output.tmp

rem search "  Duration: HH:MM:SS.mm, start: NNNN.NNNN, bitrate: xxxx kb/s"
for /F "tokens=1,2,3,4,5,6 delims=:., " %%i in (output.tmp) do (
    if "%%i"=="Duration" call :calcLength %%j %%k %%l %%m
)
goto :EOF

:calcLength
set /A s=%3
set /A s=s+%2*60
set /A s=s+%1*60*60
set /A VIDEO_LENGTH_S = s
set /A VIDEO_LENGTH_MS = s*1000 + %4
echo Video duration %1:%2:%3.%4 = %VIDEO_LENGTH_MS%ms = %VIDEO_LENGTH_S%s

Gleiche Antwort hier: So beschneiden Sie die letzten N Sekunden eines TS-Videos

digitalfootmark
quelle
Alternativ ffprobe -i "input.mp4" -show_entries format = dauer -v quiet -of csv = "p = 0" -sexagesimal
Ray Woodcock
1
ffmpeg -i abc.mp4 2>&1 | grep Duration | cut -d ' ' -f 4 | sed s/,//

gibt Ausgabe

HH: MM: SS.milisecs

Sparsh Turkane
quelle
grep, cutUnd sedsind unecessary. Siehe Iwans Antwort .
Llogan
warum unnötig ich verstehe nicht es gibt das Ergebnis
Sparsh Turkane
Weil du es einfach ffprobealleine benutzen kannst . Die Ausgabe von ffmpegdient nur zu Informationszwecken und nicht zum Parsen: Es wird nicht garantiert, dass immer dieselbe Struktur, dasselbe Format und dieselben Informationen mit verschiedenen ffmpegVersionen und verschiedenen Eingabeformaten verwendet werden.
llogan
0

Beste Lösung: Schneiden Sie den Export und erhalten Sie so etwas wie 00: 05: 03.22

ffmpeg -i input 2>&1 | grep Duration | cut -c 13-23
Mike
quelle
-1

Ich würde dies einfach in C ++ mit einer Textdatei tun und die Token extrahieren. Warum? Ich bin kein Linux-Terminal-Experte wie die anderen.
Um es einzurichten, würde ich dies unter Linux tun.

ffmpeg -i 2>&1 | grep "" > mytext.txt

Führen Sie anschließend eine C ++ - App aus, um die erforderlichen Daten abzurufen. Extrahieren Sie möglicherweise alle wichtigen Werte und formatieren Sie sie für die weitere Verarbeitung mithilfe von Token neu. Ich muss nur an meiner eigenen Lösung arbeiten und die Leute werden sich nur über mich lustig machen, weil ich ein Linux-Neuling bin und nicht gerne zu viel Skripte schreibe.

AdmiralSmith
quelle
-1

Argh. Vergess das. Es sieht so aus, als müsste ich die Spinnweben aus meiner C- und C ++ - Programmierung herausholen und stattdessen verwenden. Ich kenne nicht alle Shell-Tricks, um es zum Laufen zu bringen. So weit bin ich gekommen.

ffmpeg -i myfile 2>&1 | grep "" > textdump.txt

und dann würde ich wahrscheinlich die Dauer mit einer C ++ - App extrahieren, indem ich stattdessen Token extrahiere.

Ich poste die Lösung nicht, weil ich gerade keine nette Person bin

Update - Ich habe meinen Ansatz, um diesen Zeitstempel zu erhalten

Schritt 1 - Holen Sie sich die Medieninformationen in eine Textdatei
`ffprobe -i myfile 2>&1 | grep "" > textdump.txt`
ODER
`ffprobe -i myfile 2>&1 | awk '{ print }' > textdump.txt`

Schritt 2 - Informieren Sie sich über die benötigten Informationen und extrahieren Sie sie.
cat textdump.txt | grep "Duration" | awk '{ print $2 }' | ./a.out
Beachten Sie das a.out. Das ist mein C-Code, um das resultierende Komma abzuschneiden, da die Ausgabe ungefähr 00: 00: 01.33 ist.
Hier ist der C-Code, der stdin verwendet und die richtigen benötigten Informationen ausgibt. Ich musste die größeren und kleineren Zeichen zum Betrachten herausnehmen.

#include stdio.h #include string.h void main() { //by Admiral Smith Nov 3. 2016 char time[80]; int len; char *correct; scanf("%s", &time); correct = (char *)malloc(strlen(time)); if (!correct) { printf("\nmemory error"); return; } memcpy(correct,&time,strlen(time)-1); correct[strlen(time)]='/0'; printf("%s", correct); free(correct); }

Jetzt formatiert die Ausgabe korrekt wie 00: 00: 01.33

AdmiralSmith
quelle
-5

Sie könnten dies versuchen:

/*
* Determine video duration with ffmpeg
* ffmpeg should be installed on your server.
*/
function mbmGetFLVDuration($file){

  //$time = 00:00:00.000 format
  $time =  exec("ffmpeg -i ".$file." 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,//");

  $duration = explode(":",$time);
  $duration_in_seconds = $duration[0]*3600 + $duration[1]*60+ round($duration[2]);

  return $duration_in_seconds;

}

$duration = mbmGetFLVDuration('/home/username/webdir/video/file.mov');
echo $duration;
ManawatuHonky
quelle
-5

ffmpeg wurde durch avconv ersetzt: Ersetzen Sie einfach Louis Marascios Antwort durch avconb.

avconv -i file.mp4 2>&1 | grep Duration | sed 's/Duration: \(.*\), start.*/\1/g'

Hinweis: die zusätzliche. * Nach dem Start, um die Zeit alleine zu bekommen !!

muralisc
quelle
1
Die Fälschung " ffmpeg" aus Libav (eine Abzweigung des FFmpeg-Projekts) wurde durch eine avconvaus Libav ersetzt. ffmpegvon FFmpeg befindet sich in einer sehr aktiven Entwicklung.
Llogan