Audiolänge einer MP3 Datei erhalten ohne diese vollständig zu laden

RalleYTN

Bekanntes Mitglied
Hallöchen!
Hab mal wieder ein recht spezifisches Problem.
Ich bin gerade dabei mithilfe von JLayer und der MP3Spi Audiodateien abzuspielen.
Da es sich um Musik handelt dachte ich mir es wäre besser die Dateien zu Streamen anstatt alles über einen Clip in den RAM zu laden und einen OutOfMemoryError zu riskieren.
Der Player für die MP3 Datei soll natürlich auch fähig sein die Länge des Contents anzuzeigen.

Problem:
Ich würde für WAV Dateien die Länge wie folgt berechnen
Java:
length = (long)(1000000 * (audioInputStream.getFrameLength() / audioInputStream.getFormat().getFrameRate()));
Das funktioniert jedoch nicht, da audioInputStream.getFrameLength() bei MP3s -1 liefert.

Ich habe bereits versucht die Header mithilfe der Klassen die mit den Bibliotheken kommen auszulesen.
Java:
AudioFileFormat audioFileFormat = AudioSystem.getAudioFileFormat(this.resource);
              
if(audioFileFormat instanceof TAudioFileFormat) {
                  
   Map<?, ?> headers = ((TAudioFileFormat)audioFileFormat).properties();
   headers.forEach((key, value) -> System.out.println(key + ": " + value));
}

Ergebnis:
Code:
mp3.copyright: false
date: 2016
mp3.framesize.bytes: 1040
mp3.vbr: false
mp3.frequency.hz: 44100
mp3.framerate.fps: 38.28125
mp3.id3tag.track: 1
mp3.id3tag.v2: java.io.ByteArrayInputStream@b81eda8
mp3.channels: 2
mp3.vbr.scale: 0
mp3.version.encoding: MPEG1L3
mp3.bitrate.nominal.bps: 320000
mp3.version.layer: 3
mp3.id3tag.v2.version: 3
mp3.padding: false
mp3.header.pos: 1130
comment: ?ÿ?ww.dvdvideosoft.com?
mp3.version.mpeg: 1
mp3.mode: 1
mp3.crc: false
mp3.original: true

Jetzt weiss ich jedoch nicht weiter. :/
 

Tobse

Top Contributor
Sieht für mich so aus, als ob du da mit einer Unschärfe von +-2-3 Skunden gut hinkommen kannst:
Du kennst mp3.framerate.fps, ich vermute mal, dass das Frames Per Second ist. Du weisst durch mp3.framesize.bytes auch, dass ein Frame 1040 Frames groß ist. Wenn die ganze Datei also 3MiB (= 3.145.728 bytes) groß ist, sind es 3145728 / 1040 = ~3024 Frames und damit 3024 / 38,28125 = 79 Sekunden.

Ich kenne das MP3-Format nicht so gut. Sicher weiss ich, dass die Framegröße aufgrund der High- und Lowcuts ggü. WAV oder FLAC deutlich geringer ist und damit Speicherplatz gespart wird. Wenn aber zusätzlich noch irgendeine Kompression (wie bspw. GZip) dabei ist, wird das mit dem ausrechnen der Dauer eher schwierig.

Ein anderer Punkt: je nachdem, wo deine App läuft, brauchst du dir um die OutOfMemoryException nicht so viele Sorgen machen. Wenn du keine Referenzen zu den Dateien rumliegen lässt sollte der GC gut hinterherkommen. Und auf einem System mit mehreren GB Arbeitsspeicher kannst du ne menge MP3s in den RAM laden, bevor du ein Problem bekommst.

Natürlich kannst du nicht jedes mal die Datei in dem RAM lesen, wenn du Infos dazu möchtest. Ich vermute die gängigen Audio-Player (WMP, Groove under Windows, Rythmbox und Bashee unter Linux bspw) haben eine SQLite Datenbank, in der sie solche schwer erarbeiteten Infos zwischenspeichern. Java + SQLite geht, mit H2DB kannst du aber auch arbeiten, wenn du auf native Libraries verzichten möchtest.
 

RalleYTN

Bekanntes Mitglied
Kommt dem Ergebnis nahe hat jedoch schon bei einem 6 Sekunden clip einen Verlust von 0,5 Sekunden.
Wenn ich nicht eine Meldung mit "mark not supported" bekommen würde, dann könnt ich ganz einfach einmal durch den AudioInputStream gehen und die bytes zählen (wären an dem Punkt nämlich nicht mehr komprimiert) und danach den AudioInputStream resetten und normal weiter arbeiten.

Die Lösung hat mich auf jeden Fall ein Stück weiter gebracht, jedoch ist sie nicht genau genug.
 

RalleYTN

Bekanntes Mitglied
HEUREKA!!!
Java:
int frameLength = 0;
byte[] buffer = new byte[this.audioInputStream.getFormat().getFrameSize()];

while(this.audioInputStream.read(buffer) != -1) {
                       
   frameLength++;
}

this.audioInputStream.close();
this.audioInputStream = AbstractAudio.getAudioInputStream(this.resource, this.fileFormat);
this.length = (long)(1000000 * (frameLength / this.audioInputStream.getFormat().getFrameRate()));

Ich resette den AudioInputStream jetzt einfach indem ich ihn schließe und neu initializiere.
Die Header brauche ich nicht. Der korrekte FrameSize ist im AudioFormat gespeichert.
Um an die Gesamtmenge der Frames zu kommen lese ich einfach alle frames einzeln aus und zähle Sie.
Danach kann ich ganz normal weiterrechnen.
 

Tobse

Top Contributor
Das wird so nicht funktionieren. Read liest nicht zwangsläufig so viele bytes, wie der Buffer groß ist. Du musst den Rückgabewert von read aufsummieren und durch die FrameSize teilen, um ein akkurates Ergebnis zu bekommen.
 

dzim

Top Contributor
Könntet ihr nicht den MediaPlayer von JavaFX einbinden (https://docs.oracle.com/javase/8/javafx/api/javafx/scene/media/MediaPlayer.html), der bietet eine Methode #getTotalDuration():
The total amount of play time if allowed to play until finished.
.

Ah nee...
Retrieves the total playback duration including all cycles (repetitions).

Aber dafür: Über #getMedia() kommt man an die abzuspielenden Daten.
https://docs.oracle.com/javase/8/javafx/api/javafx/scene/media/Media.html
Und dort: #getDuration() - sollte also gut verwendbar sein! Und da man Media auch ohne den MediaPlayer erstellen kann, brauchst du keine JavaFX-GUI-Komponenten unnütz zu erstellen.
 

Tobse

Top Contributor
@dzim Und wer sagt, dass das damit die Datei nicht komplett in den RAM lädt? Und JavaFX nur wegen einer Klasse einzubinden ist es ggf. nicht wert
 

dzim

Top Contributor
Zum einen: Das sagt niemand, Zum anderen: Soweit ich die JavaDoc richtig verstanden hab, ist das wie Streaming. Aber statt grundsätzlich meiner Idee ablehnend gegenüber zu stehen, hättest du ja einfach eine kleine Anwendung implementieren können, die den Test macht und den Speicherverbrauch der JVM tracken können.

Ausserdem: "Einbinden" klingt ja fast so, als wäre dafür ein separates Modul (MAven, Gradle) nötig, was im Moment schlicht falsch wäre...
 

Tobse

Top Contributor
Den Speicherverbrauch bei einer 3MB Datei und 200MB Heapspace? Wird schwierig. Ich sehe das deshalb kritisch, weil JavaFX eine große Dependency ist (die Runtime Downloads sind ~7MB). Einfach lustig Dependencies in ein Projekt reinzukloppen, weil man nur eine Klasse braucht, macht z.B. das NodeJS/NPM Ökosystem komplett kaputt. Ich halte sowas daher für Bad-Practice.

Es wäre glaub eher angebracht, eine MP3-Library einzubinden. Die kann vmtl das gleiche, ist nicht auf am System installierte Codecs angewiesen und man kann für so Ein Projekt vmtl mehr davon benutzen. Ich wäre nicht verwundert, wenn der JavaFX Media-Player auf Linux ohne Codec nicht tut.
 

thecain

Top Contributor
javafx ist doch im jre, wenn ich mich nicht irre. Ich sehe das Problem nicht.

Ob man die Länge auslesen kann, wird mMn davon abhängen ob sie im ID3 Header ist, sonst werden es wohl nur Annäherungen sein, ohne das ganze File zu laden.
 

dzim

Top Contributor
@Tobse Ich versteh dich nicht mehr. Bist du nun dagegen, oder dafür?

Kurzum: Solange das Jigsaw-Modulsystem noch nicht da ist, ist die Media-Klasse (den MediaPlayer, also die JavaFX-GUI, die man hier überhaupt nicht braucht!) Teil des JVM und keine weitere Dependency in dem Sinne. Erst recht nicht im Sinne von NodeJS. Dagegen sind es jedoch Dependencies wie MP3Spi (auch wenn ich den Memory-Footprint-Impact für vernachlässigbar halte).

Ich denke jedoch, dass werder MP3Spi noch die Media-API von JavaFX das ganze File in den RAM-Schaufeln. Bei MP3Spi vermute ich es, bei der Media-API bin ich mir sicher, denn sie ist ja auch für Videos (FLV) gedacht, die ja durchaus auch einmal grösser als der RAM sein können, daher wird es maximal nur einen Bereich in den Speicher laden, oder aber - solange noch kein Player gestartet wurde - nur die Metadaten parsen.
 

RalleYTN

Bekanntes Mitglied
@dzim @Tobse

JavaFX dafür zu verwenden wäre Unsinn, da ich doch schon alles dafür notwendige im javax.sound.sampled package finde. Die Rechnung funktioniert und es wird kein riesen Overhead erzeugt.
 

Tobse

Top Contributor
@dzim @Tobse

JavaFX dafür zu verwenden wäre Unsinn, da ich doch schon alles dafür notwendige im javax.sound.sampled package finde. Die Rechnung funktioniert und es wird kein riesen Overhead erzeugt.
Naja, eine stabile API dafür zu haben ist auf jeden Fall Zukunftssicherer. Es geht um Separation of Concerns: Der Concern deiner Anwendung ist es, mit den Metadaten von Musikdateien einen Mehrwert für den Nutzer zu erzeugen. Mit Byte-geschubse und Dateiformaten beschäftigst du dich ja nur zwangsweise, nicht weil es Kernteil deines Business-Modells ist. Bei einer Library sieht es aber anders aus: dessen hauptsächlicher Concern sind Byte-Schubserei und Dateiformate in allen Farben und Formen.
Im Endeffekt lässt es sich der Code auf zwei Teile aufteilen: der Code, der die Metadaten besorgt und der, der mit den Daten was sinnvolles anstellt. Letzteren schreibst sowieso du, der ist aus der Diskussion. Aber wenn du für den Zweiten eine Library verwendest, hast du dafür den hochwertigeren Code in deiner fertigen Anwendung.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
O Text aus einer Textdatei rausholen, der zwischen zwei Schlüsselworten steht Allgemeine Java-Themen 4
V Umgang mit fehlenden Daten in einer Java-Datenanalyseanwendung Allgemeine Java-Themen 5
M Methodenübersicht einer Klasse einsehen Allgemeine Java-Themen 14
T JNA, Aufruf der Funktionen einer dll Allgemeine Java-Themen 5
I Vom Monolith zu Services in einer Webseite Allgemeine Java-Themen 1
W Variable Initialisierung mit dem Ergebnis einer Regex Allgemeine Java-Themen 1
O Werte einer Generic LinkedList zusammenrechenen Allgemeine Java-Themen 14
C Sortieren und Selektieren einer ArrayList<Point3D> Allgemeine Java-Themen 6
A Einzelne Objekte und Unterobjekte einer ArrayList ausgeben Allgemeine Java-Themen 53
TheSepp Wie kann man Leerzeichen aus einer Array liste entfernen? Allgemeine Java-Themen 10
B Ein Objekt einer Klasse mehreren anderen Klassen zur Verfügung stellen? Allgemeine Java-Themen 6
M Optimierung einer Methode (byte-Geraffel) Allgemeine Java-Themen 2
I Wie kann ich den Wert aus einer If abfrage ausgeben Allgemeine Java-Themen 23
S HTML einer Webseite 1:1 so bekommen wie es auch der Browser anzeigt? Allgemeine Java-Themen 14
melaniemueller Einzelne Zeile aus einer txt Datei in einem String speichern Allgemeine Java-Themen 12
L Java überprüfen lassen, ob sich ein gegebener Pfad / das Programm an sich auf einer CD oder Festplatte befindet Allgemeine Java-Themen 14
J (Geplante) Änderungen an einer Datei vorübergehend speichern und anwenden? Allgemeine Java-Themen 12
ME2002 Fragen aus einer Java Klausur Allgemeine Java-Themen 67
_user_q Obfuscate einer .jar-Datei mit ProGuard? Allgemeine Java-Themen 2
_user_q Verknüpfung einer .jar-Datei (liegt z. B. auf dem Desktop) im Autostart-Ordner erstellen? Allgemeine Java-Themen 20
C Parsen einer sich updatenden Html mithilfe von jsoup Allgemeine Java-Themen 4
E Eine Methode einer extendeten Klasse deakitivieren Allgemeine Java-Themen 12
H Performance einer Monte-Carlo-Simulation verbessern Allgemeine Java-Themen 6
LimDul Kam eine java.net.URL zu einer HashMap und ging als DNS Anfrage wieder heraus Allgemeine Java-Themen 18
E Variablen Nach Übergabe einer Variable den Constructor aufrufen Allgemeine Java-Themen 16
Zeppi NullPointerException in einer if-Abfrage Allgemeine Java-Themen 6
D Abbruch einer ViewScoped Bean in Arbeit Allgemeine Java-Themen 2
Lukas2904 Schleife mit ansteuerung einer Klasse Allgemeine Java-Themen 5
d.lumpi Aus Einer Klasse auf ein Objekt einer anderen Klasse Zugreifen Allgemeine Java-Themen 1
Lukas2904 Wie kann man cps (ClicksPerSecond) in einer GUI anzeigen lassen? Allgemeine Java-Themen 4
O Produziert das Tool "jpackage" (ab JDK 14) .exe Dateien, die auf einer Zielumgebung ohne JRE lauffähig sind ?` Allgemeine Java-Themen 7
R Lambda Expression in einer Methode execute() aufrufen (execute() ist eine Methode aus dem funktionalen Interface Command) Allgemeine Java-Themen 5
Drachenbauer wie kann ich alle instanzen einer Klasse durchsehen, ohne, dass diese in einer Liste erzeugt wurden? Allgemeine Java-Themen 11
N BlueJ Implementation einer Analoguhr Allgemeine Java-Themen 0
O Formatierte String ausgabe bei vier Variablen in einer Zeile Allgemeine Java-Themen 1
N Speicherort einer Datei im Explorer ändern Allgemeine Java-Themen 8
O Datentypen Wie kann ich den Typ einer ArrayList abfragen ? Allgemeine Java-Themen 7
O Leerzeichen und Umlaute im Pfad einer Java Applikation machen Probleme Allgemeine Java-Themen 13
H Mehrere PNG-Files in einer Datei Allgemeine Java-Themen 9
G Java Editor Löschen doppelter Zahlen einer Liste Allgemeine Java-Themen 2
J JSON Daten von einer Webseite erhalten Allgemeine Java-Themen 2
L RegEx für Teile einer Berechnung Allgemeine Java-Themen 14
L Erste Schritte TDD testen einer Methode mit injezierten Services? Allgemeine Java-Themen 12
J Zerlegen einer Zahl Allgemeine Java-Themen 6
Zrebna Wie kann man endgültig aus einer Rekursion ausbrechen? Allgemeine Java-Themen 14
MiMa Person in einer Arraylist hinzugügen mit Prüfung ? Allgemeine Java-Themen 6
Meeresgott Effizientester Weg um nach der Value einer verschachtelten Map aufzulösen Allgemeine Java-Themen 5
H Mehrere Datentypen in einer Arraylist speichern Allgemeine Java-Themen 9
MiMa Prüfziffer einer EAN Nummer berechnen Allgemeine Java-Themen 4
MiMa Erstellungsdatum einer Datei Allgemeine Java-Themen 10
Drachenbauer Wie kann ich einer existierenden Enum von außerhalb veränderte Werte zuweisen? Allgemeine Java-Themen 5
S HTML den ich von einer URL hole nicht identisch mit dem HTML im Browser Allgemeine Java-Themen 1
S Rückgabe einer HttpURLConnection für eine Seite einlesen bei der man eingeloggt ist..? Allgemeine Java-Themen 5
O Java-Applikation tut in Netbeans, als JAR nicht, wegen Pfadangaben einer benötigten Datei Allgemeine Java-Themen 8
M Hilfe bei einer Java Programmieraufgabe! Ab morgen Montag um 08:00 Uhr Allgemeine Java-Themen 5
J Algorithmen Analyse einer Schleife Allgemeine Java-Themen 6
Drachenbauer Wie finde ich den Aufrufer zu einer Methode, die sich nicht in meinem Projekt befindet? Allgemeine Java-Themen 2
J Die Letzte Zahl aus einer Text datei lesen Allgemeine Java-Themen 8
P einen public <Optinal String> in einer anderen Klasse mit einem Int vergleichen Allgemeine Java-Themen 2
A Mithilfe von einer Nummer einen Namen finden n-Beziehung Allgemeine Java-Themen 8
Scream_ilias Auf einer Website die anmeldedaten eingeben Allgemeine Java-Themen 9
V Threads Probleme beim Aufrufen von Methoden einer anderen Klasse (Threads) Allgemeine Java-Themen 14
I Lohnt sich heutzutage der Aufwand einer Portierung für MacOS Allgemeine Java-Themen 8
J Suchen von einer Scannereingabe in einem HashSet Allgemeine Java-Themen 1
M Konstruktor einer Methode Allgemeine Java-Themen 35
L Echtzeitdaten aus einer Webseite ziehen mit Java Allgemeine Java-Themen 19
V EMail, Attachments auslesen von einer Email Allgemeine Java-Themen 0
T Google Links in einer Liste Allgemeine Java-Themen 4
T Sinn einer toString Methode Allgemeine Java-Themen 3
P Durchlaufen einer Queue Allgemeine Java-Themen 9
J Größe einer CD ermitteln Allgemeine Java-Themen 10
L Operatoren Java Reflections: Alle Methoden einer Klasse aufrufen ohne Exceptions Allgemeine Java-Themen 5
H Länge einer verketteten Liste Allgemeine Java-Themen 4
B Quellcode einer Java libary finden um zu copy & paste'n Allgemeine Java-Themen 5
N Daten einer JCoTable in JTextArea anzeigen Allgemeine Java-Themen 7
sascha-sphw Java 9 module Zugriff auf eine resource einer anderen JAR Allgemeine Java-Themen 0
N Generic Type einer Generischen Klasse während der Laufzeit bekommen Allgemeine Java-Themen 2
E Erstellen einer Liste mit einer maximalen Menge an Elementen Allgemeine Java-Themen 13
M Wie kann ich ein int[] Array in einer Methode benutzen? Allgemeine Java-Themen 6
T Compiler-Fehler NoClassDefFoundError beim Laden einer Class Allgemeine Java-Themen 11
H Klassen LibGDX - Verschiedene Klassen als Value in einer Map Allgemeine Java-Themen 8
P Element einer Liste wurde hinzugefügt, aber es gibt keinen Zugriff Allgemeine Java-Themen 2
E Elemente innerhalb einer ArrayList vergleichen Allgemeine Java-Themen 33
J Einen Thread in einer Schleife Allgemeine Java-Themen 2
temi Java Programm aus einer DB laden und starten Allgemeine Java-Themen 2
J int Werte in einer anderen Klasse in Arrays speichern Allgemeine Java-Themen 3
S Hilfe bei dem Auslesen einer YAML Datei Allgemeine Java-Themen 8
D Warum kann ich eine (deflaut) Klasse aus einer Libary in einem anderen Projekt benutzen? Allgemeine Java-Themen 3
B Generelle Frage bei einer Webanwendung / Reduzierung von DB Abfragen Allgemeine Java-Themen 1
ReinerCoder Methode einer Klasse meldet Fehler "misplaced construct(s)" Allgemeine Java-Themen 13
L Fehler bei der Ausführung einer Jar Allgemeine Java-Themen 2
Javafan01 Deklarieren einer Math.random() Zufallszahl Allgemeine Java-Themen 16
A Probleme beim Verstehen einer Aufgabenstellung Allgemeine Java-Themen 11
H Laden einer (Resourcendatei) aus einem Jar-File Allgemeine Java-Themen 17
P Array einer abstrakten Klasse Allgemeine Java-Themen 4
J Teil einer URL auslesen Allgemeine Java-Themen 13
J Ordner und Datei Struktur einer War Datei Allgemeine Java-Themen 1
F Problem beim Einlesen einer Textdatei Allgemeine Java-Themen 12
J Zugriff auf erstellte Objekte einer Klasse von einer Klasse ausserhalb Allgemeine Java-Themen 3
K Gespeicherte Daten von einer LinkedList auf vier LinkedList verteilen Allgemeine Java-Themen 6

Ähnliche Java Themen

Neue Themen


Oben