Václav Kadlec 8.3.2005
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í:
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.
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.
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).
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).
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.
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:
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:
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.

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.

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.
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.
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.