Ist es in ffmpeg möglich, die Audioerweiterung beim Extrahieren (Kopieren) des Audiostreams aus einem Video automatisch zu bestimmen?
ffmpeg -i movie.mkv -vn -c:a copy audioOnly.{?}
Der Ton in movie.mkv kann jedes beliebige Format haben (mpeg3, aac, flac, wav, vorbis usw.)
Antwort1
Es gibt einen Unterschied zwischen Containern und der Kodierung. m4v ist ein Container, ebenso wie WAV, WMA, WMV, AAC usw. Sie alle unterstützen mehrere Kodierungen. Es gibt jedoch einige allgemeine Muster. ffprobe kann helfen.
Das Extrahieren von Audio aus Videodateien mit ffmpeg wird hier sehr ausführlich behandelt: https://gist.github.com/protrolium/e0dbd4bb0f1a396fcb55
Darin finden Sie ein Beispiel, wie Sie das gewünschte Ergebnis in einigen Fällen mithilfe von ffprobe und sed erzielen können:
for file in *mp4 *avi; do ffmpeg -i "$file" -vn -acodec copy "$file".`ffprobe "$file" 2>&1 |sed -rn 's/.Audio: (...), ./\1/p'`; done
Auf der verlinkten Seite schien das Obige durch die HTML-Kodierung beschädigt zu sein. Ich habe versucht, es zu reparieren. Es könnte wahrscheinlich für eine einzelne Datei vereinfacht werden auf:
ffmpeg -i "myfile.m4v" -vn -acodec copy "myfile".`ffprobe "myfile.m4v" 2>&1 |sed -rn 's/.Audio: (...), ./\1/p'`
Wenn Sie jedoch weder sed noch eine Bash-Shell verwenden, funktioniert dies nicht. (Unter Windows funktioniert es also nicht.) Es funktioniert auch nicht, wenn die Kodierung in der Videodatei nicht allgemein einer Dateierweiterung zugeordnet werden kann. Unter Windows könnten Sie wahrscheinlich eine Powershell oder ein VBScript verwenden, das dasselbe tut.
Antwort2
Sie können die Erweiterung nicht automatisch erkennen, aber FFMPEG kann automatisch erkennen, welcher Muxer für einen bestimmten Ausgabecontainer verwendet werden soll, und einige Muxer (hauptsächlich für Audio und Untertitel) können nur Streams eines bestimmten Typs (Codec) verarbeiten.
Außerdem versucht FFMPEG, den „besten“ (normalerweise am besten geeigneten) Stream auszuwählen, wenn Sie ihn nicht ausreichend angeben. Und wenn Sie keine Neukodierung zulassen, sind die einzigen geeigneten Streams diejenigen, die vom Muxer unterstützt werden.
*.AC3
Das bedeutet, wenn Sie FFMPEG beispielsweise anweisen, die Datei ohne Neukodierung zu speichern ( -c copy
), aber nicht angeben, welcher Stream verarbeitet werden soll -map
, wird versucht, den ersten geeigneten Stream zu verwenden oder einen Fehler zu melden, wenn kein solcher Stream vorhanden ist. Und wenn Sie -map
einen Parameter verwenden, um einen ungeeigneten Stream anzugeben, wird ebenfalls ein Fehler gemeldet.
So können Sie diese Funktionen beispielsweise nutzen, um nur den DTS-Stream zu extrahieren, unabhängig davon, an welcher Position in der Datei er sich befindet:
ffmpeg -i in.mkv -c copy out.dts
Oder wenn Sie wissen, dass Ihre Datei DTS-, AC3- und AAC-Streams enthält, aber nicht wissen, in welcher Reihenfolge:
ffmpeg -i in.mkv -c copy -map 0:a:0 out-1.dts
ffmpeg -i in.mkv -c copy -map 0:a:0 out-1.ac3
ffmpeg -i in.mkv -c copy -map 0:a:0 out-1.aac
ffmpeg -i in.mkv -c copy -map 0:a:1 out-2.dts
ffmpeg -i in.mkv -c copy -map 0:a:1 out-2.ac3
ffmpeg -i in.mkv -c copy -map 0:a:1 out-2.aac
ffmpeg -i in.mkv -c copy -map 0:a:2 out-3.dts
ffmpeg -i in.mkv -c copy -map 0:a:2 out-3.ac3
ffmpeg -i in.mkv -c copy -map 0:a:2 out-3.aac
Dadurch werden alle genannten Dateien erstellt, aber nur diejenigen, die einem geeigneten Stream in der Eingabedatei entsprechen, enthalten den Stream. Danach müssen Sie nur noch die leeren Dateien löschen und die verbleibenden verwenden.
Im Windows-Befehl (Batch) können Sie stattdessen dies überprüfen ERRORLEVEL
(entweder 0
auf Erfolg oder 1
auf Fehler) und nur die Dateien behalten, die erfolgreich extrahiert wurden:
ffmpeg -i in.mkv -c copy -map 0:a:0 out-1.dts
if [1] == [%ERRORLEVEL%] del out-1.dts
ffmpeg -i in.mkv -c copy -map 0:a:0 out-1.ac3
if [1] == [%ERRORLEVEL%] del out-1.ac3
...
Beachten Sie jedoch, dass für bestimmte Multiplexer einige Einschränkungen gelten können:
- Der MP3-Muxer funktioniert ohne
-map
Parameter nur für Dateien, die genau einen MP3-Stream enthalten. Um MP3 aus einer Datei mit mehreren Audiodaten zu extrahieren, müssen Sie also mehrere Aufrufe verwenden-map 0:a:X
und jeden Audiostream ausprobieren, bis Sie den richtigen gefunden haben. - Der AC3-Multiplexer wird bei AC3 verwendet, kann jedoch auch MP3- und MP2-Streams verarbeiten. Wenn die Datei also sowohl AC3- als auch MP3/MP2-Streams enthält, werden beide (oder der erste) extrahiert und die Erweiterung ignoriert.
- Möglicherweise gibt es noch andere Grenzen, aber ich habe sie noch nicht gefunden.
Aktualisieren:Hier sind einige Ideen, wie Sie das Problem mit AC3- und MP2/MP3-Streams lösen können.
In Windows Batch können Sie %~zX
die Größe einer Eingabedatei lesen und if A LSS B
zwei Zahlen vergleichen.Für Linux prüfenDas.
Idee A) Sie können alle (Audio-)Streams aus der Datei als out-1.ac3, out-2.ac3 usw. extrahieren und dann den größten suchen (vorausgesetzt, AC3 ist größer als MP2 oder MP3 gleicher Länge).
ffmpeg -i in.mkv -c copy -map 0:a:0 out-0.ac3
ffmpeg -i in.mkv -c copy -map 0:a:1 out-1.ac3
call keep_larger.cmd out-0.ac3 out-1.ac3 out.ac3
Und die keep_larger
Charge wird sein:
if %~z1 LSS %~z2 goto del
del %2
ren %1 %3
goto end
:del
del %1
ren %2 %3
:end
Jetzt wird die größte Datei als out.ac3 gespeichert
Idee 2) Das Programm LAME kann WAVE- und MPEG-Audio als Eingabe akzeptieren (und in MP3 konvertieren), schlägt jedoch bei AC3 fehl. Sie können also ca. 5 Minuten des Streams extrahieren und LAME diese verarbeiten lassen (verwenden Sie Parameter -f
für die schnellste Verarbeitung). Bei WAVE oder MPEG ist das Ergebnis groß (1 MB+), bei AC3 jedoch sehr klein (ca. 5 kB).
ffmpeg -i in.mkv -c copy -map 0:a:0 -t "5:00" out.mp2
lame -f out.mp2 out.mp3
call keep_if_larger.cmd 500000 out.mp3
if not exist out.mp3 ren out.mp2 out.ac3
if not exist out.ac3 del out.mp2
if not exist out.ac3 del out.mp3
Die keep_if_larger
Charge wird sein:
if %~z2 LSS %1 del %2
Wenn der ausgewählte Stream nun AC3 war, konnte LAME ihn nicht in ein akzeptabel großes MP3 konvertieren und wir konnten MP2 in AC3 umbenennen. Andernfalls löschen wir die MP2- und MP3-Datei und versuchen es mit einem anderen Stream.
Antwort3
Da ich auf dieselben Anforderungen gestoßen bin, habe ich das folgende PHP-Skript erstellt:
isset($argv[1]) || exit('You have to specify a file.');
$file = new SplFileInfo($argv[1]);
$file->isFile() || exit('File not found.');
$input = '"' . $file->getPathname() . '"';
// full path to the containing folder
$full_dir = $file->getPathInfo()->getRealPath();
// filename only: without path, without extension
$base_name = $file->getBasename('.' . $file->getExtension());
// deduce file extension from the audio stream
$output_extension = get_output_extension($file->getPathname());
// combine all that stuff
$output = '"' . $full_dir . '/' . $base_name . '.' . $output_extension . '"';
exec('ffmpeg -i ' . $input . ' -vn -acodec copy ' . $output);
function get_output_extension($file)
{
$file = '"' . trim($file, '"') . '"';
$stream_info = shell_exec('ffprobe -v quiet -print_format json -show_streams -select_streams a ' . $file);
$data = json_decode($stream_info);
if (!isset($data->streams[0]->codec_name)) {
exit('Audio not found - ' . $file);
}
$audio_format = $data->streams[0]->codec_name;
$output_extensions = [
'aac' => 'm4a',
'mp3' => 'mp3',
'opus' => 'opus',
'vorbis' => 'ogg',
];
if (!isset($output_extensions[$audio_format])) {
exit('Audio not supported - ' . $file);
}
return $output_extensions[$audio_format];
}
Dieses Skript ist so konzipiert, dass es mit Dateien umgehen kann, die sich nicht im aktuellen Verzeichnis befinden, unabhängig davon, ob auf sie durch vollständige oder relative Pfade verwiesen wird.
Ich bin nicht wirklich zufrieden, da der Code für eine so einfache Aufgabe zu lang ist. Wenn ihn jemand prägnanter machen kann, ist er herzlich willkommen :)
Tatsächlich handelt es sich beim komplexesten Code nicht um ffmpeg, sondern umSplFileInfo(mit einerschrecklichAPI, wie das obige Skript zeigen kann).
Für ein verwandtes Skript hatte ich das gute altepathinfo()
ein Versuch, aber es ist lokalisierungsabhängig und hat unerwartet einige Dateien übersehen, also ist es für mich ein No-Go.