Bis vor kurzem wurden im Web-UI nur cover von mp3s angezeigt. @Wolle ist vor ein paar Wochen meiner Anregung nachgekommen, dies auch für andere Formate wie flac, ogg, opus bibliothekseitig zur Verfügung zu stellen. Vielen Dank für diese Arbeit!
Die Anzeige von nativen flac covern habe ich dann espuinoseitig umgesetzt, tueddy hat dies im Code übernommen und @tueddy hat selbst noch die Anzeige von m4a Covern umgesetzt.
Nun fehlt jetzt noch die Anzeige von ogg, vorbis, opus covern. Diese sind im Unterschied zu den obigen Dateiformaten base64 codiert und liegen nicht in einem Stück, sondern in mehreren Segmenten innerhalb der Datei vor (auch nicht-native flac cover haben diese Eigenschaft).
Ich habe bereits mit tueddy gesprochen, von seiner Seite aus spricht nichts gegen die Übernahme meiner Code-Änderungen (s.u.). Aber er hat mir vorgeschlagen, meinen Änderungsvorschlag zunächst hier im Forum vorzustellen. Das will ich hiermit machen.
Analog zu audio_id3image habe ich eine audio_oggimage geschrieben, in der
- das base64 codierte cover chunkweise decodiert wird,
- das decodierte cover im SD-Karten Ordner /.cache/file.path() gecacht wird (decodiert wird natürlich nur, falls das cover nicht bereits gecacht vorliegt)
zu 1: „Dekodieren“
- die Segmente werden in Chunks der Größe 2048 (kann man beliebig wählen, muss aber base64 kompatibel sein) dekodiert. Da das Ganze auch funktionieren soll, wenn man eine chunkSize wählt, die größer als ein Segment ist und die Segmente ohnehin die base64-Blöcke oft mittendrin trennen, ist das auch kein Einzeiler. Wer das chunkweise und mit ganzen Blöcken einfacher decodieren kann, möge gern einen Vorschlag posten.
Natürlich wäre der Code viel kürzer, wenn man zunächst alle Segmente einliest und an einem Stück decodieren lässt. Das ging bei meinem Board (D32 pro LiFePO4) auch mit riesigen Covern (über 1MB) problemlos, aber ggf. nicht bei allen anderen Boards, die ESPuino unterstützt. tueddy hat mir zu einer chunkweisen Dekodierung geraten. Zeitlich dauert das chunkweise Dekodieren nur minimal länger als das Dekodieren in einem Stück, die chunkSize sollte aber mindestens 1024 Bytes sein, für noch kleinere Chunks dauert es dann doch etwas länger. - mittels
char *encodedChunk = (char *)x_malloc(chunkSize);
wird Speicher im SPIRAM allokiert, falls vorhanden, dadurch dauert das Dekodieren insgesamt etwa 10% länger, als wenn man im heap allokiert, aber ich denke das ist verkraftbar - ich habe den base64 Decoder von Base64 decode snippet in C++ - Stack Overflow (keine copyright claims gefunden, „fastest algorithm out there AFAIK“) verwendet, da dieser mehr als 10 mal schneller ist als die standard base64 decoder, die man auf dem esp32 benutzt, wie z.B. mbedtls. Dieser base64 Decoder steht derzeit einfach vor der geschriebenen audio_oggimage. Sollte man diesen noch z.B. in common.h schreiben, oder gar eine eigene .h Datei für machen?
[Zur zeitlichen Info: Das Dekodieren inkl. Abspeichern der decodierten Bilddatei dauert bei normalen covern der Größe 40-80kB um die 250ms, die anderen Decoder brauchen dann schon um die 3 Sekunden, bei größeren Bildern entsprechend länger]
zu 2: „Cachen“
- zunächst ist abzuwägen, ob überhaupt gecacht werden soll.
Das Cachen hat den Vorteil, dass ein einmal decodiertes Cover bei erneutem Abspielen der zugehörigen Datei nicht nochmal decodiert werden muss, also Rechenzeit spart. Allerdings braucht es etwas Speicherplatz auf der SD-Karte und der Code ist etwas länger, insbesondere wenn man in einem eigenen Ordner /.cache die Coverbilder speichert. - dann ist abzuwägen, wo gecacht werden soll. Man könnte das decodierte Coverbild im selben Ordner speichern, entweder unter demselben Namen (+.img) oder mit demselben Namen (+.img) aber führendem Punkt „.“, sodass die Datei unsichtbar ist für den Anwender. Da in der Web-UI Dateien mit führendem Punkt jedoch angezeigt werden, und ich das für den Anwender unschön finde, wird die decodierte Datei jetzt für den Anwender ungemerkt in /.cache/file.path() gespeichert, ähnlich wie z.B. auch thumbnails auf einem PC gespeichert werden. Da der Pfad dorthin ggf. noch nicht existiert, muss er erstellt werden, einen command wie mkdir_p() scheint es leider nicht zu geben (?), daher etwas umständlicher (geht das einfacher?).
Falls ihr euch den Code anschaut, bedenkt bitte, dass ich kein Programmierer bin, sondern das Programmieren in der Schule gelernt habe.
Was haltet ihr von dem Vorschlag? An welchen Stellen gibt es Verbesserungspotential oder alternative Herangehensweisen? Gerade von der Wahl der besten Variablenarten oder Speicherverwaltung habe ich ehrlich gesagt keine Ahnung.
Leider bin ich (wie @laszloh und viele andere auch) vor kurzem auf github gesperrt worden, kann so also derzeit kein PR zur Diskussion reinstellen. Deshalb hier ein Patch mit allen Änderungen, den ihr z.B. einfach mittels
git apply <.patch file>
in den aktuellen dev applien könnt (Endung .txt vorher entfernen):
0001-Add-coverimage-support-for-ogg-vorbis-opus-files-in-.patch.txt (6,7 KB)
Vielen Dank fürs Durchlesen und Kommentieren.