Autor |
Beitrag |
Jakob Schöttl
Beiträge: 929
Erhaltene Danke: 1
Delphi 7 Professional
|
Verfasst: Mi 12.07.06 13:13
Super, Vielen vielen Dank Gausi.
Da hast du dir jetzt viel mühe gegeben, und ich habs auch super verstanden.
Ich brauch das übrigens für ein Programm, das alle MP3s sucht, und eine ExcelTabelle anlegt (mit OLE). Später will ich, dass man die Daten auch in Excel ändern kann, und diese dann von meinem Programm wieder in die MP3s geschrieben werden.
|
|
Gausi
Beiträge: 8535
Erhaltene Danke: 473
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Mo 14.08.06 15:25
Gewissermaßen als Nebenprodukt bei der Weiterentwicklung meines MP3-Players ist eine neue Version dieser Unit entstanden.
Warum es diesmal direkt zwei Varianten gibt, ist etwas schwer zu erklären. Der Unterschied kommt nur dann zum Vorschein, wenn man auch "exotische" MP3-Dateien damit bearbeiten will. Also z.B. koreanische, russische oder hebräische.
Benutzen die ID3v2Tags Unicode für die Textinformationen, so sind beide Versionen gleichwertig. Benutzen sie aber den lokalen Zeichensatz (was eigentlich nicht so sein sollte), dann kann die INT-Version diesen entsprechend konvertieren - entweder so, wie es der User vorgibt (vorausgesetzt ist eine passende Eingabemöglichkeit für die Option im Programm), oder aber bis zu einem gewissen Grad automatisch anhand des Dateinamens (wenn dieser Unicode-Zeichen enthält, und gewisse Parameter übergeben werden, die der User der Endanwendung ebenfalls eingeben können sollte).
Dafür ist aber eine recht umfangreiche De- und Entkodierungs-Unit nötig, die alleine das Programm um ca. 200-300kb größer macht. Daher gibt es auch eine abgespeckte Version.
Ich hoffe, dass es die Demos den Unterschied klar machen, und wenn nicht, dann hilft evtl. ein Blick in die mp3s mit einem Hexeditor. Wichtig dabei ist die "00" oder die "01" unmittelbar vor den Textinformationen. (Also in den Demo-mp3s das siebte Byte nach den Frame-IDs "TIT2", "TPE1", "COMM" und "TALB").
Steht da eine "01", kann man die WE-Version benutzen. Steht da eine "00", und dahinter unlesbarer Krempel, dann braucht man die INT-Version.
Für "einheimische mp3s" reicht die WE-Version locker aus und bietet keinen Voreil gegenüber der INT-Version.
Download wie immer im ersten Beitrag.
|
|
Calculon
Beiträge: 676
Win XP Professional
Delphi 7 PE, Delphi 3 PRO
|
Verfasst: Do 14.09.06 02:22
Hallo Gausi!
Ich habe eine Frage bzgl. der Bilder, die mit einer mp3-Datei verknüpft werden. Seit dem ich den Windows Media Player 11 beta benutze, lädt der Player von irgendeiner Quelle automatisch die Cover meiner mp3-Lieder herunter. Da das überraschend gut funktioniert wurde ich sofort ein Fan dieses Features. Ich dachte die Bilder werden mit in den Tags abgespeichert. Aber mit deinem Tool kann man sie nicht mehr auslesen. Auch mit anderen Playern, wie z.B. winamp konnte ich den mp3-Files die Bilder nicht mehr entlocken. Nur interessehalber frage ich, weißt du wie das beim WMP funktioniert und vor allem, wo die Coverbilder abgelegt werden?
Gruß
|
|
Gausi
Beiträge: 8535
Erhaltene Danke: 473
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Do 14.09.06 08:57
Wo der Windows-Media-Player die Cover her hat, weiß ich nicht. Wahrscheinlich gibt es auf irgendeinem MS-Server eine recht umfangreiche Datenbank, auf dem für jedes Album ein entsprechendes Cover hinterlegt ist. Möglicherweise holt er sich die von einem Onlineshop, mit dem MS zusammenarbeitet. Zumindest steht in der 10er Version über dem Cover, was angezeigt wird "Bei MSN Music kaufen"
Wo der WMP die Bilder ablegt, weiß ich noch weniger. Kann der WMP die Bilder aus den mp3s auch auf einem anderen Computer (ohne Verbindung ins Netz) anzeigen? Wenn dem nicht so ist, dann werden die Bilder wahrscheinlich nur irgendwo in der Medienbibliothek des Players gespeichert, oder sogar gar nicht - d.h. das geht nur mit Verbindung ins Netz.
Wenn du da keine Testmöglichkeit hast, oder dir nicht sicher bist, kannst du mir gerne auch ein mp3 mit Bild per Mail schicken, ich werde mir das dann mal genauer ansehen. (Wenn du Angst vor Raupkopiererei und Knast hast, kann ich dir gerne eine Liste mit meinen CDs schicken, evtl. gibt es da Überschneidungen.)
Möglicherweise speichert der WMP die Bilder in einem Format in die Tags ab, die ich nicht verarbeiten kann. Ich habe die Beta 11 nicht, und werde sie mir deswegen auch nicht installieren. Da gibt es bessere Player, die eher meinen Bedürfnissen entsprechen.
_________________ We are, we were and will not be.
|
|
Gausi
Beiträge: 8535
Erhaltene Danke: 473
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Do 14.09.06 12:11
Es tut mir unendlich leid, aber die Version 0.2 hatte einen groben peinlichen Schnitzer, der möglicherweise den gesamten ID3v2-Tag unbrauchbar machte.
Den Fehler habe ich heute durch Zufall entdeckt, und er sollte nun behoben sein. Beim Umstellen auf Unicode habe ich an einer Stelle eine Codezeile aus Versehen gelöscht oder vergessen. Sie ist nun wieder drin.
_________________ We are, we were and will not be.
|
|
0xCC
Beiträge: 150
|
Verfasst: Sa 16.09.06 16:39
hi, wie wäre es compilerschalter bzgl TNT-Kompos einzubauen ?
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| {$DEFINE USE_TNT_COMPOS} uses SysUtils, Classes, Windows {$IFDEF USE_TNT_COMPOS}, tntcompo1, tntcompo2{$ENDIF};
type {$IFNDEF USE_TNT_COMPOS} TTNTFileStream = TFileStream; {$ENDIF}
...
{$IFNDEF USE_TNT_COMPOS} function WideFileExists(s:string):boolean; begin result := fileexists(s); end; {$ENDIF} |
so könnte man mit einer simplen änderung {.$DEFINE USE_TNT_COMPOS} die nutzung der TNTs abschalten.
Nachtrag:
übrigens wird durch den verweis auf die unit im dpr-file deines demoporgrammes die compilierung erst möglich, wenn man die unit in das selbe verzeichnis wie das demo-projekt kopiert, nicht aber wenn sie in einem bibliothekspfad vorliegt.
|
|
Gausi
Beiträge: 8535
Erhaltene Danke: 473
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Sa 16.09.06 17:20
In der DP kam auch schon der Vorschlag beide Versionen über Compilerschalter zu vereinen, da sie sich auch nur an einigen wenigen Stellen unterscheiden.
Das würde ich dann hiermit kombinieren, wenn ich mal wieder Zeit und Lust habe, mich an diese Unit dranzusetzen...
_________________ We are, we were and will not be.
|
|
terryk
Hält's aus hier
Beiträge: 4
|
Verfasst: Mi 27.09.06 09:34
Titel: "Fehler" in TMpegInfo.LoadFromStream
Hallo!
Ich habe ein Problem in MpegInfo.LoadFromStream gefunden. Bei bestimmten MP3-Files wird eine Exception (Fehler bei Bereichsprüfung) in
Delphi-Quelltext 1: 2: 3:
| tmpMpegHeader := GetValidatedHeader(Buffer, bufferpos); |
ausgelöst. Anscheinend liegt es daran, dass in der Routine GetValidatedHeader der "Beginn" des MPEG-Headers fälschlicher weise erkannt wird und dann bitrateindex=0 ist, was die Exception in
Delphi-Quelltext 1:
| Result.bitrate := MPEG_BIT_RATES[Result.version][Result.layer][bitrateindex]; |
auslöst. Der Fehler tritt nur dann auf, wenn bufferpos=0 ist, also von Anfang an gesucht wird, ohne vorher (wie in der Beispielanwendung) den ID3v2-tag zu lesen. Im Beispiel NormaleDemo funktioniert es, weil in BtnShowInfosClick folgende Reihenfolge eingehalten wird, der Tag existiert und somit die bufferpos auf Id3v2Tag.size statt auf 0 gesetzt wird:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| Id3v2Tag.ReadFromStream(FS);
if Not Id3v2Tag.exists then <= Ja, der Tag existiert FS.Seek(0, sobeginning) else FS.Seek(Id3v2Tag.size, soFromBeginning); <= Position des Streams NICHT null
MpegInfo.LoadFromStream(FS); <= Auslesen ist OK |
Wenn man aber nur die MPEG-Infos will und im gleichen Beispiel folgendes macht, geht es bei manchen MP3s schief:
Delphi-Quelltext 1: 2:
| MpegInfo.LoadFromStream(FS); <= Auslesen erzeugt manchmal Exception |
Wie kann man den MPEG-Header in GetValidatedHeader verlässlicher erkennen?
Gruß und danke!
|
|
Gausi
Beiträge: 8535
Erhaltene Danke: 473
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Mi 27.09.06 09:55
terryk hat folgendes geschrieben: | Wie kann man den MPEG-Header in GetValidatedHeader verlässlicher erkennen? |
Eine Möglichkeit wäre, nach dem Bestimmen von result.version das einzufügen: Delphi-Quelltext 1: 2: 3: 4: 5:
| if result.version=0 then begin result.valid := false; exit; end; |
Allerdings ist es sehr empfehlenswert, immer zunächst den ID3-Tag zu lesen, aus folgenden Gründen:
- es ist schneller. Wenn der Tag nicht da ist, macht es keinen Unterschied, aber wenn er da ist, muss ohne vorherige Erkennung des Tags der ganze Tag bitweise untersucht werden, bis ein MPEG-Header gefunden wird
- es ist sicherer. Es ist theoretisch möglich, in den ID3v2-Tag mehr Informationen als nur Texte zu speichern. Theoretische sollte es sogar möglich sein, in den v2Tag ein anderes mp3-File zu speichern, z.B. mit einem Audiokommentar des Interpreten. Ohne vorheriges Lesen des Tags würdest du diese MPEG-Frames finden, nicht die des eigentlichen Stückes.
Zu deinem Problem: Ich werde das wohl demnächst mal ausbessern, würde dich aber bitten, mir ein Beispiel-mp3 zu schicken (per PN oder eMail), wo das Verfahren bisher schiefgeht und diese Exception auftritt.
_________________ We are, we were and will not be.
|
|
terryk
Hält's aus hier
Beiträge: 4
|
Verfasst: Mi 27.09.06 11:33
Hallo!
Habe die MP3 als PN geschickt, ist leider 11MB groß.
Die Prüfung auf die Version alleine reicht nicht, da in diesem Fall (der geschickten MP3) das Byte nach $FF nämlich $E0 ist und die Version 3 (bzw 2.5) und somit gültig ist. Ich prüfe deshalb auf die zwei nach MPEG-Standard reservierten Bit-Kombinationen BB=01 für die Version und CC=00 für den Layer (dieser wird dann 4-0=4).
Also folgender Workaround als Vorschlag (damit lösen meine MP3-Files keine Exceptions mehr aus!):
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| function TMpegInfo.GetValidatedHeader(aBuffer: TBuffer; position: integer): TMpegheader;
... bla bla ...
Result.Layer := 4-((abuffer[position+1] shr 1) and 3); Result.protection := (abuffer[position+1] AND 1)=0;
if (Result.version = 0) or (Result.Layer = 4) then begin Result.valid := False; Exit; end;
... bla bla ... |
Gruß
|
|
terryk
Hält's aus hier
Beiträge: 4
|
Verfasst: Mo 30.10.06 11:57
Titel: Bug + Bugfix in TID3v2Tag.ReadFrames
Hallo Gausi!
Habe in MP3FileUtils_WE v0.2a (Westeuropa) noch einen Bug gefunden, der zu Fehlern bei Bereichsprüfung führt. Bugfix siehe Code unten.
Gruß
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30:
| function TID3v2Tag.ReadFrames(From: LongInt; Stream: TStream): TMP3Error;
... bla bla ...
with FFrames[newframeIDX] do begin setLength(Header,length(aHeader)); move(aHeader[0], Header[0], length(Header)); Data := nil; if FrameSize > 0 then begin SetLength(Data, FrameSize); Stream.ReadBuffer(Data[0], FrameSize); end; FFrameID := FrameIDstr; FSize := FrameSize; end;
... bla bla ...
end; |
|
|
Gausi
Beiträge: 8535
Erhaltene Danke: 473
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Mo 30.10.06 12:08
Danke, das werde ich demnächst einbauen. Allerdings ist das nicht wirklich ein Bug, der zu einer fehlerhaften Darstellung führt. Zumindest nicht bei korrekten Tags, denn:
www.id3.org hat folgendes geschrieben: | A tag must contain at least one frame. A frame must be at least 1 byte big, excluding the header. |
Da man davon aber natürlich nicht ausgehen sollte, ist die Meldung durchaus berechtigt. (In der anderen Version dürfte der Fehler übrigens auch drin sein )
_________________ We are, we were and will not be.
|
|
terryk
Hält's aus hier
Beiträge: 4
|
Verfasst: Mo 30.10.06 12:44
Titel: Noch ein Bugfix
Hallo Gausi!
Ja, Probleme gibt es i.d.R. nur bei eingeschalteter Bereichs-/Überlaufprüfung, aber manchmal hängt mein Programm deswegen. ich habe noch einen anderen "Fehler" gefunden und behoben; im XingHeader wird auf Felder in abuffer zugegriffen, die größer als dessen Länge sind (siehe Code unten):
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| function TMpegInfo.GetXingHeader(aMpegheader: TMpegHeader; aBuffer: TBuffer; position: integer ): TXingHeader;
...bla...
if Length(abuffer) <= (position + xing_offset + 11) then begin Result.valid := False; Exit; end;
if (abuffer[position+xing_offset]=$58) AND (abuffer[position+xing_offset+1]=$69) AND (abuffer[position+xing_offset+2]=$6E) AND (abuffer[position+xing_offset+3]=$67) then begin
...bla... end; |
|
|
Gausi
Beiträge: 8535
Erhaltene Danke: 473
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Mo 30.10.06 13:17
Wenn du so weiter machst, kennst du dich bald besser in meinem Code aus als ich .
Wenn ich die nächste version veröffentliche, werde ich wohl das eine oder andere von dir einbauen - mit einem entsprechendem Hinweis natürlich
Wobei es mir zur Zeit bei dem Problem von eben (Framsize = 0) sinnvoller erscheint, dann den Datenteil künstlich auf 1-Byte aufzublasen. Sonst könnte es unter Umständen an anderer Stelle zu Problemen führen. Aber dafür müsste ich noch malgenauer in den Code gucken .
_________________ We are, we were and will not be.
|
|
Manina
Beiträge: 44
Win 7 Pro
RAD Studio 2010 Pro
|
Verfasst: Di 21.11.06 02:22
Hallo Gausi !
Etwas ähnliches passierte mir nach folgendem Szenario:
1. Auswahl einer mp3.Datei
2. Löschen v1 und v2-Tag --> "Clear all tags"
3. Speichern
4. Anhängen von "Cover(front)" und "Cover(back)" (ok. waren ziemlich große Jpeg's... btw. spielt die Größe der Bilder eigentlich eine Rolle ?)
5. wieder speichern
6. Programm beenden --> nur die beiden Bilder im Id3v2-Tag, sonst nix...
7. Programm neu starten und gleiche Datei auswählen --> Bilder wurden angezeigt
8: Id3v2-Tag löschen ----->>>> INTEGERÜBERLAUF
Der Debugger sagte mir, in
TID3v2Tag.RemoveFromStream
kam die Exception an der Stelle
// shorten the file by the size of the tag
Stream.Seek(-FTagSize, soFromEnd);
Ich habs behoben, indem ich sowohl "private FTagSize" als auch "property size" von LongWord zu Int64 gemacht habe.... Allerdings weiß ich jetzt net, hängt die Exception nur mit der eingeschalteten Überlaufprüfung zusammen, oder wäre es nicht besser, generell zu Int64 zu wechseln bei den heutigen Dateigrößen, gerade von Bildern ?
Gruß, Bernd.
|
|
Manina
Beiträge: 44
Win 7 Pro
RAD Studio 2010 Pro
|
Verfasst: Di 21.11.06 02:27
Achja noch ne Frage
Unbekannte Frames bleiben ja erhalten (so sie denn nicht Framesize = 0 haben ). Wie kann ich feststellen, WELCHE unbekannten Frames er denn so findet ? Mir sind so Sachen wie PRIV, WOAS, WOAR usw. untergekommen - die hätte ich gerne einfach in einer Liste angezeigt, daß sie da sind, aber halt net gehandled werden...
Gruß Bernd.
|
|
Gausi
Beiträge: 8535
Erhaltene Danke: 473
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Di 21.11.06 09:49
Zu den JPEGs: Prinzipiell spielt die Größe der Bilder keine Rolle. Ich muss aber nochmal genauer nachsehen, ob die maximal erlaubte Framegröße evtl. überschritten werden kann. Die dürfte aber auch bei mehreren MB liegen.
Ein Ändern von LongWord zu Int64 ist unnötig, wenn nicht sogar gefährlich. Die Größenangaben von Tag und Frames im ID3v2Tag sind nunmal 4Byte groß - der enstprechende Datentyp in Delphi ist dann LongWord. Dieser geht laut OH von 0..4,294,967,295. D.h. man bekommt erst bei Bildgrößen von 4 Gigabyte Probleme (eigentlich schon bei ca. 500MB, da im Tag die Integer nur mit 28 Bit gespeichert werden).
Ob der Fehler nun an der Überlaufsprüfung liegt, oder ob (und wenn ja wo genau) da ein Fehler steckt, kann ich jetzt nicht auf Anhieb sagen. Die Stelle (und ein paar andere auch) wollte ich bei Gelegenheit aber sowieso ändern.
Zu den unbekannten Frames: Ja, da könnte man evtl. was machen. WOAS, WOAR sind iirc URLs (die man eigentlich sowieso einbauen könnte ). PRIV sind Private Frames und können mit einer entsprechenden Beschreibung mehrfach vorkommen. Eine mögliche Auflistung der nicht verarbeiteten Frames ist eine gute Idee.
_________________ We are, we were and will not be.
|
|
Manina
Beiträge: 44
Win 7 Pro
RAD Studio 2010 Pro
|
Verfasst: Di 21.11.06 11:30
nochmal zur TagSize:
Vielleicht sollte man Beides kombinieren ? Die internen Variablen kann man durchaus zu Int64 machen, damit es keine Compilerprobleme wie Überlauf usw. gibt. Denn was würde passieren, wenn zB. FTagSize >= $80000000 ist ? Ein
Stream.Seek(-FTagSize, soFromEnd)
pointed dann doch nur ein "paar" Bytes vom Dateiende rückwärts...
Ich glaube, genau das ist mir passiert. Daher der Gedanke mit den langen Integers.
Beim Hinzufügen neuer Frames muß man dann halt darauf achten, daß die "echte" FrameSize von 32 Bit nicht überschritten wird.
Gruß, Bernd
|
|
Gausi
Beiträge: 8535
Erhaltene Danke: 473
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Di 21.11.06 11:55
Hmm... Ich hab das nochmal mit dem Testprojekt ausprobiert. Ich habe zwei Bilder mit je rund 2MB eingefügt und wieder gelöscht - ohne Probleme.
Hattest du das Problem bei Benutzung eines der Demo-Projekte, oder bei einem eigenen? Wie groß waren die Bilder? Kannst du den Fehler reproduzieren, und mir evtl. eine Kopie der Datei mit dem Bilder-Tag, der zu dem Überlauf führt per Mail schicken?
ich vermute nämlich fast, dass da beim Schreiben des Tags irgendwas schiefläuft.
_________________ We are, we were and will not be.
|
|
Manina
Beiträge: 44
Win 7 Pro
RAD Studio 2010 Pro
|
Verfasst: Di 21.11.06 12:20
Gerade merke ich, der Fehler hat gar nix mit irgendwelches Bildern zu tun...
Also...
Ich habe Deine "Normal-Demo" benutzt; in den Projektoptionen der IDE sind alle Prüfungen eingeschaltet. Das Szenario war jetzt:
1. Datei auswählen (Datei enthält gar keine Bilder !)
2. Id3v1-Tag löschen (id3v1Tag.RemoveFromFile(Edit1.Text))
3. Zeige Infos (TForm1.BtnShowInfosClick(Sender: TObject)) --> v1-Tag ist leer
4. Id3v2-Tag löschen (id3v2Tag.RemoveFromFile(Edit1.Text)) --> INTEGERÜBERLAUF, obwohl TagSize nur 1627 ist (???)
Wieder passiert es beim Stream.Seek(-FTagSize, soFromEnd);
Die Datei schick ich Dir per Mail... Sie enthält, so wie ich beim Laden gesehen habe, außer den üblichen Frames nur einen WXXX der Länge 2.
Wohlgemerkt, ich wollte keine einzelnen Frames löschen, sondern den kompletten v2-Tag.
|
|
|