Umíme to s Delphi: 140. díl – formát a vnitřní struktura ID3v2 tagů

V dnešním pokračování seriálu se pokusíme dále prokousat do hloubky problematiky MP3 souborů. Konkrétně se zaměříme velmi podrobně na druhou verzi ID3 tagů. Definujeme si jejich formát a prozkoumáme jejich vnitřní strukturu. V závěru článku potěším řadu čtenářů, kteří mě v emailech žádají o offline verzi seriálu: upozorním na několik projektů, které se pro offline prohlížení nabízejí.

Na samotný úvod neuškodí lehké shrnutí. V minulém článku jsme se podívali na to, jakým způsobem jsou definovány ID3v2 tagy, jak se liší od jejich předchůdců (v1) a v čem spočívají jejich výhody. Výsledkem našeho zkoumání bylo následující shrnutí:

  • ID3v2 tag je z implementačního hlediska vlastně jakýmsi kontejnerem, například jako soubory PNG, který umožňuje vkládání nových „kousků“, částí, v závislosti na tom, jak postupuje vývoj souboru a jeho zpracování,
  • umístění tagu na začátku hudebních souborů znamená pohodlnou možnost streamování skladeb,
  • obsahuje jakousi pojistku nazvanou „nesynchronization scheme“, která zabraňuje přehrávačům nekompatibilním s ID3v2 v tom, aby e pokoušely přehrát tag,
  • maximální velikost tagu je 256 MB, maximální velikost jednoho rámce je pak 16 megabajtů,
  • ID3v2 tagy šetří prostorem jak je to jen možné, data jsou určitým způsobem komprimována,
  • tagy podporují kódování Unicode,
  • technologie není ve své podstatě striktně zaměřena na hudební audiosoubory, lze ji využít i pro ostatní druhy audia,
  • přichází s předdefinovanými rámci pro uložení všech relevantních informací, například jméno skladatele, interpreta, název skladby a alba, druh média, informace o autorských právech apod. Kromě toho si můžete nadefinovat jakýkoliv vlastní rámec pro uložení čehokoliv, co vás o skladbě zajímá,
  • může obsahovat nejen slova, ale také informace o rozmístění slov v toku skladby (známé karaoke). To vše je možné v libovolném jazyce,
  • může nést informace o hlasitosti skladby a o jakýchkoliv jiných nastavení ekvalizéru,
  • může být připojen k databázi tyou CDDB,
  • může obsahovat nejen obrázky, ale ve své podstatě jakékoliv jiné soubory, které chceme vložit,
  • podporuje odkazy a webové adresy.

V dnešním článku se podíváme více do hloubky a popíšeme si vnitřní implementační strukturu ID3 tagu.

Vnitřní struktura tagu ID3v2

Hned na úvod bych rád zdůraznil, že veškerý následující text čerpá z dokumentu uvedeného na webové adrese http://www.id3.org/id3v2.4.0-structure.txt, kam se také můžete obrátit pro případné podrobnosti. Protože uvedený dokument svým rozsahem značně převyšuje kapacitní možnosti našich článků, setkáte se zde na stránkách Živě jen se stručným výtahem.

Dokument popisuje (a my tedy popisujeme též) nejnovější verzi ID3v2 tagů, přesně verzi ID3v2.4.0.

Na samotný úvod bych ještě rád podotkl, že dnešní článek je primárně určen pro pokročilejší uživatele. Neříkám tím, že začátečníci mají hned skončit se čtením; některé informace jsou nicméně techničtějšího rázu a pro začátečníky by nemusely být stoprocentně srozumitelné. Reaguji tím na požadavky mnoha čtenářů, kteří se domnívají, že seriál je příliš "začátečnický", že jim nemá co nabídnout a že bych měl občas oslovit i pokročilejší publikum.

Přehled ID3v2 tagů

ID3v2 je obecný formát tagů pro audiosoubory, který umožňuje uložit metadata (data popisující samotný obsah audiosouboru) přímo uvnitř onoho audiosouboru. Až potud se nedozvídáme nic, co bychom ještě nevěděli z předchozího dílu. ID3v2 tag je ponejvíce zaměřen na soubory kódované technologiemi MPEG-1/2 layer, MPEG-1/2 layer II, MPEG-1/2 layer III a MPEG-2.5, nicméně může fungovat i s jinými kódováními audiosouborů, stejně jako může fungovat zcela samostatně jako metaformát pro audio.

Aby mohl formát fungovat a zároven přinášet co největší flexibilitu a rozšiřitelnost, je konstruován jako kontejner pro různé bloky informací. Tyto bloky jsou nazývány rámce (frames). Formát všech rámců nemusí být nutně znám, a tak software, který tag zpracovává, může narazit na zcela neznámý formát (nebo druh) informací. Taková událost nesmí vyústit v chybné zpracování rámce nebo celého tagu.

Na začátku každého rámce je tedy unikátní a předdefinovaný identifikátor, popisovač velikosti rámce (který umožňuje zpracujícímu softwaru přeskočit ne konec rámce) a dále pole pro flagy (flags fields). Flagy popisují podrobnosti o kódování a několik dalších podrobností.

Pořadí bitů v tagu ID3v2 je takové, že nejvíce významný byt (most significant bit, MSB) je vždy uveden na prvním místě. Pořadí bajtů u vícebajtových čísel je potom takové, že nejvýznamnější bajt (most significant byte) je uveden na prvním místě (kódování je známé jako big endian).

Obecná struktura tagu

O obecné struktuře ID3 tagu jsme si již mnohé řekli minule, proto jen zopakujme, že povšechně se na ID3v2 tag můžeme dívat jako na strukturu vypadající zhruba takto:

+--------------------------------------+
|     Hlavička (Header) - 10 bajtů     |
+--------------------------------------+
| Rozšířená hlavička (Extended Header) |
|     (proměnná délka, NEPOVINNÁ)      |
+--------------------------------------+
|             Rámce (Frames)           |
|            (proměnná délka)          |
+--------------------------------------+
|               Padding                |
|     (proměnná délka, NEPOVINNÁ)      |
+--------------------------------------+
|            Patička (Footer)          |
|         (10 bajtů, NEPOVINNÁ)        |
+--------------------------------------+

Obecně lze říci, že padding a patička jsou ve vztahu vzájemného vyloučení (nemohou se vyskytnout obě najednou, podrobnosti viz níže).

Formát základních sekcí

V následující kapitole se podrobněji zadíváme na formát jednotlivých sekcí uvedených výše ve schémátku. Začneme hlavičkou.

Hlavička (Header)

Jak je patrné ze schématu, hlavička je prvním elementem ID3v2 tagu. Zabírá vždy 10 bajtů a její vnitřní formát je následující:

ID3v2/file identifier "ID3"
ID3v2 version $04 00
ID3v2 flags %abcd0000
ID3v2 size 4 * %0xxxxxxx

První tři bajty tagu obsahují vždy znaky "ID3", což je jakýsi identifikátor začátku tagu. Ihned za těmito znaky jsou dva bajty vyhrazené pro pro verzi tagu. První bajt označuje hlavní číselné označení verze (major version), zatímco druhý bajt je číslo revize. V uvedeném příkladu je očividně použita verze ID3v2.4.0. Podle definice nebude nikdy číslo verze mít hexadecimální hodnotu FF.

Jak už to tak bývá, všechny revize jsou zpětně (nikoliv však nutně dopředněú kompatibilní. Software, který zpracovává např. ID3 tagy verze ID3v2.4, by se měl chovat tak, že v případě nalezení tagu s označením vyšší verze (nikoliv revize), např. ID3v2.5.0 jednoduše přeskočí (a nebude se pokoušet nijak zpracovávat) celý tag.

Pojďme se dále podívat na to, co se skrývá v poli označeném jako ID3v2 flags. V současnosti jsou používány čtyři flagy (přičemž pro další čtyři je vyhrazen prostor, podívejte se výše), které umožňují popsat následující informace:

  • bit a - používá se k popisu tzv. unsynchronization. Pozorní čtenáři si možná vzpomenout, že tímto jevem jsme se zabývali už posledně, když jsme si říkali, že tzv. unsynchronization scheme je možné proto, abychom zabránili nekompatibilním přehrávačům přehrávat ID3 tag jako součást audiodat. Flag má hodnotu 1 v případě, že tento mechanismus je použit pro všechny rámce (podrobnosti později).
  • bit b - používá se k řečení, zda hlavička (Header) je následována rozšířenou hlavičkou (Extended Header). Flag je nastaven na 1 v případě, že tomu tak je.
  • bit c - indikátor experimentálního statusu tagu. Tento flag je nastaven na hodnotu 1 pokaždé, když je celý ID3 tag v experimentálním stádiu.
  • bit d - indikátor přítomnosti patičky. Flag je nastaven na hodnotu 1 v případě, že na samotném konci tagu je umístěna patička.

Specifikace dále hovoří o tom, že všechny další čtyři flagové bity musí být nastaveny na hodnotu 0 (stejně jako je tomu v naší ukázce výše). Pakliže některý z tagů není nastaven na nulu, může být celý tag nečitelný pro přehrávače, které neznají přesný význam flagů.

Poslední složka hlavičky je informace o velikosti tagu. Tento údaj je uložen jako 32bitový synchsafe integer (podrobnosti později), používající celkově 28 významných bitů (reprezentujících velikosti do 256 MB, což je také maximální velikost tagu).

Velikost ID3v2 tagu je součtem velikosti rozšířené hlavičky, sekce padding a všech rámců. Pokud je přítomna patička, rovná se tento údaj hodnotě (celková délka - 20) bajtů, v opačném případě (celková délka - 10) bajtů.

Z informací, které jsme si uvedli o hlavičce ID3v2 tagu vyplývá, že existnce tagu v audiosouboru může být detekována prostřednictvím následujícího vzoru:

$49 44 33 yy yy xx zz zz zz zz

Z uvedených informací také plynou některé pravidla, která lze použít pro ověření, že jsme opravdu nalezli ID3v2 tag:

  • hodnota bajtu yy je vždy menší než $FF (vzpomeňte, že verze nikdy není FF),
  • xx je bajt obsahující flagy,
  • bajt zz je vždy menší než $80.

Praktická ukázka - detektor empétrojek s tagem ID3v2

Abychom se v celém článku nevěnovali jen a jen teorii, odskočíme si na chvíli do Delphi a implementujeme velmi jednoduchý prográmek.

Použijme-li informace uvedené v předchozích odstavcích, můžeme směle vytvořit jednoduchou aplikaci, která detekuje, zda empétrojka obsahuje ID3v2 tag či nikoliv.

Vytvořená aplikace je vskutku primitvní, neošetřuje žádné chybové stavy a neobsahuje žádný sofistikovaný test existence ID3v2 tagu. Jediné, co udělá, je, že načte empétrojku do paměti a projde načtené informace za účelem nalezení výše uvedeného vzoru a otestování výše uvedených pravidel. Je zřejmé, že ani splnění těchto pravidel nezaručuje, že soubor opravdu obsahuje platný ID3v2 tag.

Stejně tak jsem si vědom skutečnosti, že aplikace bude sice fungovat ve většině případů, pro několik nepříznivých (byť nepravděpodobných) situací to však platit nebude.

Klepněte pro větší obrázek

Aplikaci neberte jako ukázku reálného testování přítomnosti ID3v2 tagu, spíše jen jako osvěžení od teoretického popisu v předchozí části článku.

Aplikace obsahuje jen dvě komponenty: tlačítko (Button) a dialog pro otvírání souboru (OpenDialog). Po klepnutí na tlačítko se spustí procedura, která zkontroluje zvolený soubor a otestuje naplnění uvedených pravidel. Toť vše.

Klepněte pro větší obrázek

Zdrojový kód

Jako obvykle, ani dnes vás neochudím o zdrojový kód naší aplikace:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, StrUtils;

type
  TForm1 = class(TForm)
    OpenDialog1: TOpenDialog;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure ZjistiID3v2tag(JmenoSouboru: TFileName);
Var
  Soubor: File;
  Pozice: Integer;
  Buffer: array[1..500000] of char;
  Precteno: Integer;
  Zprava: Byte;

begin
  Assign(Soubor, JmenoSOuboru);
  Reset(Soubor, 1);
  Zprava := 0;

  repeat
    BlockRead(Soubor, Buffer, 500000, Precteno);

    Pozice := Pos(`ID3`, Buffer);
    if Pozice > 0 then begin
      Zprava := 1;
      if ord(Buffer[Pozice+3]) = $FF then Zprava := 2;
      if ord(Buffer[Pozice+7]) >= $80 then Zprava := 2;
      if ord(Buffer[Pozice+8]) >= $80 then Zprava := 2;
      if ord(Buffer[Pozice+9]) >= $80 then Zprava := 2;
      if ord(Buffer[Pozice+10]) >= $80 then Zprava := 2;

      break;
    end;
  until (Precteno = 0);

  Case Zprava of
    0 : ShowMessage(`Soubor neobsahuje ID3v2 tag.`);
    1 : ShowMessage(`Soubor obsahuje platny ID3v2 tag.`);
    2 : ShowMessage(`Soubor se tvari, ze obsahuje ID3v@ tag, ten je vsak neplatny.`);
  end;

  CloseFile(Soubor);
end;

 

procedure TForm1.Button1Click(Sender: TObject);
begin
  if OpenDialog1.Execute then
    ZjistiID3v2tag(OpenDialog1.FileName);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Caption := `Test existence tagu ID3v2`;
  Button1.Caption := `Zjisti`;
end;

end. 

Offline verze seriálu - shrnutí možností

Ještě předtím, než se dnes rozloučíme, vás upozorním na několik dalších možností, které máte pro sledování tohoto seriálu.

Ve svých mailech se mě často ptáte, jestli není možné poskytnout nějakým, jakýmkoliv způsobem jednotlivé kapitoly seriálu v offline verzi, abyste nebyli nuceni číst online nebo abyste nemuseli soubory stahovat jeden po druhém.

Nejprve tedy připomenu, že si kdykoliv můžete stáhnout skvěle zpracovanou offline verzi seriálu vytvořenou panem RNDr. Petrem Brantem. Stahovat můžete přímo ze stránek pana Branta, adresa je http://brant.wz.cz/.

Kromě této varianty pak nově máte ještě další možnost. Pan Pavel Polívka vytvořil program, který po svém stažení a nainstalování dokáže stahovat a spravovat všechny díly pro offline sledování a celou řadu dalších zajímavých a užitečných činností. Program je opravdu velmi povedený, má hodně funkcí a všem zájemcům o offline sledování seriálu jej doporučuji. Instalační soubory můžete stáhnout z adresy projektu.

Poslední upozornění, kterého se ode mě dnes dočkáte, se ještě týká programu pana Polívky. Na adrese http://diskuse-umime-to-s-delphi.wz.cz/index.php najdete diskusní fórum, které obsahuje několik kategorií a v němž se můžete vyjádřit jak ke kvalitě seriálu, tak i k požadavkům na výše uvedenou aplikaci. Prostřednictvím tohoto fóra můžete kontaktovat jak autora programu, tak i mě a ostatní čtenáře.

Přes řadu možností, které se vám nabízejí pro offline sledování seriálu bych vás poprosil, abyste z pochopitelných důvodů četli co možná nejčastěji jeho online verzi. Dostatečná čtenost je nejdůležitějším argumentem pro zachování seriálu a jeho další zveřejňování na stránkách serveru Živě.

Oběma autorům offline verzí, panu Brantovi i panu Polívkovi, nicméně tímto upřímně děkuji za jejich úsilí o zpřístupnění seriálu dalšímu spektru čtenářů. Za svou práci si zaslouží ohromné ocenění, protože z ní nic nemají, přesto ji dělají velmi intenzivně a se skvělými výsledky. Pánové, vážím si toho, že vás můj seriál zaujal natolik, že neváháte věnovat svůj volný čas jeho podpoře. Díky.

Na závěr

V dnešním dílu jsme se podívali na vnitřní strukturu tagů ID3v2. Vzhledem k rozsahu specifikace jsme se dnes nedostali dál než k hlavičce tagů, proto budeme za týden pokračovat.

Témata článku: Software, Programování, Unicode, Rámec, Díl, Karaoke, Fields, Celková délka, Uložený vzor, Formát, Flag, Vnitřní prostor, Následující aplikace, Tag, FF, Offline, Struktura, Vytvořená aplikace, Vnitřní struktura

Určitě si přečtěte

Budoucností Windows 10 je Fluent Design. Takto bude jednou vypadat celý systém

Budoucností Windows 10 je Fluent Design. Takto bude jednou vypadat celý systém

** Fluent Design je vzhled, do kterého postupně Microsoft převleče celý systém ** Staví na průhlednosti a velkých plochách ** Do Windows 10 se z části dostane už zítra při vydání podzimní aktualizace

Včera | Stanislav Janů | 134


Aktuální číslo časopisu Computer

Nový seriál o programování elektroniky

Otestovali jsme 17 bezdrátových sluchátek

Jak na nákup vánočních dárků ze zahraničí

4 tankové tiskárny v přímém souboji