Táto stránka pre svoju správnu funkčnosť vyžaduje súbory cookies. Slúžia na authentifikáciu návštevníka, analýzu návštevnosti a reklamnú personalizáciu.
logo
Prihlásenie / Registrácia
mobile

Zavrieť
 

Pod lupou: ID3 Tag

V dnešnom článku si zoberieme pod lupu ID3 tagy v hudobných súboroch, povieme si niečo o ich vzniku, využití a verziách.
V dnešnom článku si zoberieme pod lupu ID3 tagy v hudobných súboroch, povieme si niečo o ich vzniku, využití a verziách.

Čo to vlastne ID3 tag je a ako vznikol?
Z technického hľadiska, sa jedná o úložisko metadát, pôvodne vytvorené pre zvukový formát MP3. Dôvodom jeho vzniku bol fakt, že štandard MP3 súborov neobsahoval miesto, kde by sa dali relevantné metadáta uschovávať. (Naschvál som napísal slovné spojenie „relevantné metadáta“, keďže formát obsahuje niekoľko príznakov true/false príznakov, ktoré by sa dali považovať za metadáta, no majú špecifický význam). Avšak, ako pridať do nejakého súboru extra informácie tak, aby ho nepoškodili? (V dobe keď ID3 tag vznikol, existoval formát MP3 už 3 roky a existovalo už množstvo prehrávačov / editorov ktoré ho podporovali).

S riešením prišiel Eric Kemp (známy aj pod pseudonymom NamkraD), ktorý proste pridal extra údaje na koniec súboru. Takáto úprava pre väčšinu prehrávačov nepredstavovala žiadny problém, keďže všetky údaje v súbore ostali nedotknuté. Táto myšlienka sa rýchlo ujala a postupne sa podpora ID3 tagov rozšírila do prakticky všetkých prehrávačov.

Verzie

Samozrejme formát ID3 neostal len pri jedinej verzii. Postupne sa začalo narážať na obmedzenia pôvodného návrhu a tak sa začal návrh rozširovať. V súčasnosti existujú 2 hlavné verzie ID3 tagov, označované ako ID3v1 (pôvodný) a ID3v2 (nový). V nasledujúcich riadkov si vysvetlíme princíp ich fungovania a rozdiely medzi nimi.

ID3v1

Prvotná verzia ID3 tagu, je definovaná ako 128 bajtový (znakový) blok údajov na konci súboru. Aby ho bolo možné jednoducho zistiť, sú jeho prvé 3 znaky reťazec „TAG“. Zvyšných 125 bajtov je rozdelených nasledovne:
Názov skladby – 30 bajtov
Interpret – 30 bajtov
Názov albumu – 30 bajtov
Rok – 4 bajty
Komentár – 30 bajtov
Žáner – 1 bajt

Pozor, je však nutné pamätať na to, že v tomto prípade platí 1 znak = 1 bajt. Čiže „dvojznaky“, ktoré používa napríklad UTF-16 nemôžeme chápať ako 1 znak. Vo všeobecnosti sa odporúča používať len tlačiteľné znaky dolnej polovice ASCII tabuľky.

V prípade, ak niektorá z hodnôt je kratšia ako jej maximálna dĺžka (čo bude takmer vždy), je potrebné vyplniť zvyšný voľný priestor bajtami s hodnotou 0. (Pozor, nie „0“ z ASCII tabuľky, ktorá má hodnotu 48)

Hodnota reprezentujúca žáner je dlhá len 1 bajt, čiže nie je do nej možné zapísať žáner v textovej forme. Pre tento účel je vytvorený špeciálny zoznam, v ktorom sú jednotlivé žánre očíslované a tie sú následne použité ako hodnota v ID3 tagu. Pôvodný číselník obsahoval 80 hodnôt (0 – 79), neskôr bol neoficiálne rozšírený na 192 hodnôt (0 – 191). (Ich kompletný zoznam je dostupný napríklad na stránke anglickej verzie wikipédie: > link <). Toto rozšírenie sa však nedostalo do štandardu.

ID3v1.1

Prvá verzia ID3 dostala ešte jedno drobné vylepšenie. Špecifikácia prvej verzie hovorí o pevnej dĺžke tagu a všetko miesto v nom je vyhradené jednotlivým hodnotám, neostalo miesto na veľké vylepšenia bez porušenia spätnej kompatibility.

Aj v tejto zdanlivo neriešiteľnej situácii sa našiel niekto, kto našiel cestu. Bol ním Michael Mutschler, ktorý dokázal do tagu ešte „vpašovať“ číslo skladby v rámci albumu. Riešenie je založené na dvoch predpokladoch.

Prvý predpoklad je ten, že 30 znakov, ktoré sú vyhradené pre poznámku sú aj tak málo, aby mohli obsahovať nejaký zmysluplný údaj. Druhý predpoklad vychádza z faktu, že podľa pôvodnej špecifikácie sa má prebytočné miesto v hodnotách vyplniť nulami. Čiže je pravdepodobné, že ID3 parser v prehrávači načítava jednotlivé znaky z hodnôt len dokým nenarazí na prvú nulu (keďže to signalizuje, že ostatné pozície sú prázdne).

Riešením je teda pridať informáciu o čísle skladby na koniec vyhradeného miesta na poznámku. Prehrávač, ktorý nepozná takto upravený tag, bude pravdepodobne nový údaj ignorovať. Ak by ho náhodou neignoroval, nič sa nedeje, pribudne len číslo skladby v poznámke. Aby sme mali zaručené, že posledný bajt v poznámke je číslo skladby a nie časť poznámky (teoreticky môže mať poznámka rovných 30 znakov), je vždy pred číslom skladby znak 0. Takže štandard ID3v1.1 umožňuje len 28 znakovú poznámku.

Neoficiálne rozšírenia ID3v1

Okrem oficiálneho štandardu ID3v1 existujú aj jeho neoficiálne rozšírenia, v ktorých sa vývojári pokúšali obísť obmedzenia v štandarde. Keďže ich podpora v prehrávačoch je otázna, nemá zmysel sa im dopodrobna venovať, no pre úplnosť tohto článku uvediem aspoň pár informácii o nich. Medzi najznámejšie neoficiálne rozšírenia patria tzv. Enhanced TAG a „ID3v1.2“, pričom oba fungujú na rovnakom princípe. Rovnako ako ID3v1 majú pevne určené dĺžky a pevne určenú štruktúru. Vkladajú sa do MP3 súboru pred ID3 tag a identifikujú sa pomocou začiatočného reťazca „TAG+“ a „EXT“ na relevantnej pozícii oproti začiatku ID tagu.

ID3v2.2

ID3v2.2 bola prvou verejnou verziou nástupcu ID3v1. Pri jej návrhu si tvorcovia dali za cieľ maximálnu možnú rozšíriteľnosť a zároveň zachovanie kompatibility so staršími prehrávačmi. Narozdiel od svojho predchodcu, nie je umiestnený na konci súboru, ale na jeho začiatku (najčastejšie), keďže štruktúra ID3v2 je špeciálne navrhnutá tak, aby ho staršie prehrávače ignorovali a nepokúšali sa ho prehrať. (bližšie to popisuje tento dokument: > link <)

ID3v2 je svojou podstatou kontajnerom na dáta, ktoré sú organizované v tzv. frame-och, ktoré obsahujú jednotlivé hodnoty. Veľkosť jedného frame-u môže byť až 16 MB a celkovo tag môže mať veľkosť až 256 MB. Obsah frame-ov nie je limitovaný len na text, bežne sa do neho ukladajú aj obrázky (napríklad obrázok obalu albumu). Oproti ID3v1 bola pridaná aj podpora unicode v textoch, čiže odpadáva problém s diakritikou.

Hlavička ID3v2 tagu začína textom „ID3“, nasleduje číslo verzie, ktoré je zložené z dvoch bajtov. Prvý bajt hovorí o čísle verzie (major version) a druhý reprezentuje revíziu (revision number). Nasleduje jeden bajt, ktorý slúži na uschovanie špecifických príznakov (flags). V tejto verzii sa využívajú len jeho prvé 2 bity:
- Prvý bit značí použitie tzv. „unsynchronisation scheme“, ktorá sa použije v prípade, ak byt tag svojimi dátami mohol narušiť funkčnosť súboru.
- Druhý bit značí použitie kompresie.

Posledné 4 bajty obsahujú údaj o dĺžke tagu.

Podľa špecifikácie musí tag obsahovať aspoň jeden frame, pričom poradie jednotlivých frame-ov nie je pevne určené, môžu byť akomkoľvek poradí

Samotné frame-y mají 6 bajtovú hlavičku. Prvé 3 bajty slúžia ako identifikátor a zvyšné hovoria o jeho dĺžke. Pokiaľ identifikátor začína písmenami X, Y, Z jedná sa o frame určený pre experimentálne účely. V samotnom štandarde je definovaných 63 typov frame-ov.
Napríklad:
TXT – Autor(y) textu
TT2 – Názov skladby
TP1 – Interpret(i)
TP2 – Skupina
TYE – Rok
TPB – Vydavateľ
TLE – Dĺžka skladby
TCR – Copyright
TXX – Užívateľsky definovaný text
ULT – Text skladby
SLT – Text skladby s časovaním v skladbe
WAR – Webová stránka interpreta

(Kompletný zoznam nájdene v špecifikácii > link <)

ID3v2.3

Vo verzii 2.3 boli nanovo predefinované príznaky v hlavičke tagu:
- Prvý príznak ostal rovnaký
- Druhý príznak hovorí o existencii rozšírenej hlavičky
- Tretí príznak hovorí, že tag je v tzv. experimentálnom stave.

Rozšírená hlavička môže byť nosičom dopľnujúcich informácii, napríklad CRC-32 kontrolného súčtu

Novú štruktúru dostali aj samotné frame-y.
Ich identifikátor rozšírený na 4 bajty, je nasledovaný ďalšími štyrmi bajtmi pre dĺžku a pridané boli aj 2 bajty slúžiace ako príznaky (flags). Príznaky hovoria o tom, či je frame skomprimovaný, šifrovaný, určený len na čítanie alebo informujú ako sa má správať parser tagu, ak je pre neho neznámy a pod.

Štandard definuje 74 typov frame-om.

ID3v2.4

Posledná verzia štandardu pre ID3v2 vylepšila princíp ukladania tagu do súboru a pre rýchlejšie načítanie tagu pridala aj jeho pätičku. Pätička je nepovinná a jej existencií hovorí novopridaný štvrtý bit v príznakoch hlavičky. Vylepšenia sa dočkala aj rozšírená hlavička, ktorá po novom obsahuje aj informácie o pravidlách ktoré spĺňajú frame-y.

Deväť typov frame-om bolo označených za zastaralé a osem z nich bolo nahradené novými. Celkovo bolo do špecifikácie pridaných 18 nových typov.

Programové spracovanie v C#

Verzie tagu sme si popísali, teraz si ukážeme ako ich programovo čítať. Pre ID3v1 si vytvoríme vlastnú triedu, pre ID3v2 kvôli väčšej komplexnosti použijeme knižnicu tretej strany.

Otvoríme si Visual Studio a vytvoríme nový projekt konzolovej aplikácie s názvom ID3Test.

Pre načítanie ID3v1 si vytvoríme triedu v samostatnom súbore ID3v1.cs

Zdrojový kód:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;

namespace ID3Test
{
    class ID3v1
    {
        //Konstanty
        private const int TAGPosition = -128;
        private const string TAGID = "TAG";

        public string Title = "";
        public string Artist = "";
        public string Album = "";
        public string Year = "";
        public string Comment = "";
        public byte Track = 0;
        public int Genre = 0;

        public static bool Exists(string Filename)
        {
            if (!System.IO.File.Exists(Filename))
                return false;

            FileStream fs = null;
            bool Ret = false;
            try
            {
                fs = File.OpenRead(Filename);
                long lngth = fs.Length - 128;
                fs.Seek(-128, SeekOrigin.End);
                string Head = ReadValue(fs, 3);
                Ret = (Head == TAGID);
            }
            catch
            {
                Ret = false;
            }
            finally
            {
                if (fs != null)
                {
                    fs.Close();
                }
            }
            return Ret;
        }

        public static ID3v1 ReadTag(string Filename)
        {
            FileStream fs = null;
            ID3v1 Ret = null;
            try
            {
                if (System.IO.File.Exists(Filename))
                {
                    fs = File.OpenRead(Filename);
                    long lngth = fs.Length - 128;
                    fs.Seek(-128, SeekOrigin.End);

                    string Head = ReadValue(fs, 3);
                    if (Head == TAGID)
                    {
                        Ret = new ID3v1();
                        Ret.Title = ReadValue(fs, 30);
                        Ret.Artist = ReadValue(fs, 30);
                        Ret.Album = ReadValue(fs, 30);
                        Ret.Year = ReadValue(fs, 4);

                        string Comment = ReadValue(fs, 30);
                        if (Comment.Length == 30
                            && Comment[Comment.Length - 2] == '\0' && Comment[Comment.Length - 1] != '\0')
                        {
                            Ret.Comment = Comment.Substring(0, 28).Trim();
                            Ret.Track = Convert.ToByte(Comment[Comment.Length - 1]);
                        }
                        else
                        {
                            Ret.Comment = Comment;
                        }

                        Ret.Genre = fs.ReadByte();
                    }
                }
            }
            catch
            {
                Ret = null;
            }
            finally
            {
                if (fs != null)
                {
                    fs.Close();
                }
            }

            return Ret;
        }

        private static string ReadValue(FileStream fs, int ValueLength)
        {
            //Kontrola, ci sa nepokusame nacitat viac ako je k dispozicii
            if (fs.Position + ValueLength > fs.Length)
            {
                ValueLength = (int)(fs.Length - fs.Position);
            }

            if (ValueLength <= 0)
                return "";

            byte[] Buffer = new byte[ValueLength];

            int Read = fs.Read(Buffer, 0, (int)ValueLength);

            return TrimZeros(System.Text.Encoding.ASCII.GetString(Buffer, 0, Read));
        }

        private static string TrimZeros(string Value)
        {
            return Value.Trim(new char[] { '\0' });
        }
    }
}

Trieda je zložená z pomocných konštant, premmenných s hodnotami tagu a štyrmi statickými metódami.
Asi najpodstatnejšou je metóda ReadValue, ktorá zo zvoleného stream-u načíta zadaný počet bajtov,
skonvertuje ich na textový reťazec a pomocou metódy TrimZeros odstráni prebytočné nulté znaky.
Práve metódu ReadValue budeme používať na načítanie konkrétnych častí z ID3 tagu.

Metóda Exists slúži na overenie existencie ID3v1 tagu v súbore. Otvorí súbor, preskočí na relevatnú pozíciu (TAGPosition) a prečíta 3 nasledujúce znaky. Ak sa zhodujú s konštantou TAGID, vieme, že v súbore je tag prítomný.

A ostala nám ešte metóda ReadTag ktorá načíta samotný tag do objektu ID3v1.

V súbore program.cs vytvoríme metódu ReadID3v1 v ktorej náš nový objekt použijeme.

Zdrojový kód:
private static void ReadID3v1(string Filename)
        {
            if (ID3v1.Exists(Filename))
            {
                ID3v1 Tag = ID3v1.ReadTag(Filename);
                if (Tag != null)
                {
                    Console.WriteLine("Nazov skladby: " + Tag.Title);
                    Console.WriteLine("Interpret: " + Tag.Artist);
                    Console.WriteLine("Album: " + Tag.Album);
                    Console.WriteLine("Rok: " + Tag.Year);
                    if (!String.IsNullOrEmpty(Tag.Comment))
                    {
                        Console.WriteLine("Komentar: " + Tag.Comment);
                    }
                    Console.WriteLine("Zaner: " + Convert.ToString(Tag.Genre));
                    if (Tag.Track != 0)
                    {
                        Console.WriteLine("Cislo skladby: " + Convert.ToString(Tag.Track));
                    }
                }
                else
                {
                    Console.WriteLine("Pri nacitani ID3v1 tagu doslo k chybe.");
                }
            }
            else
            {
                Console.WriteLine("Subor neobsahuje ID3v1 tag");
            }
        }

ID3.NET
Umiestnenie NuGet Package Managera

Týchto pár riadkov sa nám stačilo na načítanie ID3v1. Pri ID3v2 to už takto ľahko nepôjde, preto si pomôžeme externou knižnicou.

Otvoríme si NuGet Package Manager (v menu: Tools -> NuGet Package Manager -> Manage NuGet Packages for Solution..., prípadne obdobná cesta
podľa verzie Visual Studio) vyhžadáme a nainštalujeme balík ID3.NET.

Potrebné namespace-y si pridáme do časti using v Program.cs:

Zdrojový kód:
using Id3;
using Id3.Frames;

Výpis aplikácie

Z importovanej knižnice budeme potrebovač triedy Mp3, Id3Tag z namespace Id3 a CommentFrame z namespace Id3.Frames.
Práca so samotnými objektami knižnice je jednoduchá. Pomocou objektu Mp3 si načítame informácie o súbore a zistíme, či obsahuje tag
požadovanej verzie. Ak áno, načítame si ho do objektu Id3Tag s ktorého už vieme pohodlne načítač všetky potrebné údaje.
Niektoré údaje môžu byč vo forme listu (napríklad komentáre), preto údaje budeme čítač postupne oddelíme ich čiarkou.

Po vzore metódy ReadID3v1 si vytvoríme ReadID3v2:

Zdrojový kód:
private static void ReadID3v2(string Filename)
        {
            Mp3 file = new Mp3(Filename, Mp3Permissions.Read);
            if (file.HasTagOfVersion(Id3Version.V23))
            {
                Id3Tag Tag = file.GetTag(Id3Version.V23);

                if (Tag.Title != null)
                    Console.WriteLine("Nazov skladby: " + Tag.Title.Value);

                if (Tag.Band != null)
                    Console.WriteLine("Interpret: " + Tag.Band.Value);

                if (Tag.Album != null)
                    Console.WriteLine("Album: " + Tag.Album.Value);

                if (Tag.Year != null)
                    Console.WriteLine("Rok: " + Tag.Year.Value);

                string Comments = "";
                if (Tag.Comments != null)
                {
                    foreach (CommentFrame Frame in Tag.Comments)
                    {
                        if (Comments != "")
                            Comments += ", ";

                        Comments += Frame.Comment;
                    }
                }

                if (Comments != "")
                    Console.WriteLine("Komentar: " + Comments);

                if (Tag.Genre != null)
                    Console.WriteLine("Zaner: " + Convert.ToString(Tag.Genre.Value));

                if (Tag.Track != null)
                    Console.WriteLine("Cislo skladby: " + Tag.Track.Value);
            }
            else
            {
                Console.WriteLine("Subor neobsahuje ID3v2 tag");
            }
        }

Teraz môžeme volania oboch metód pridať do Main

Zdrojový kód:
static void Main(string[] args)
        {
            string Filename = @"[cesta_k_suboru]\test.mp3";

            Console.WriteLine("ID3v1");
            ReadID3v1(Filename);
            Console.WriteLine();

            Console.WriteLine("ID3v2");
            ReadID3v2(Filename);
            Console.WriteLine();

            Console.ReadLine();
        }

Do premennej Filename pridáme cestu k testovaciemu mp3 súboru a aplikáciu môžeme spustiť.

Zdrojový kód aplikácie môžete sťahovať z nasledujúcej linky: > link <

Záverom

V prípade, ak by ste aj budúcnosti ocenili podobný typ článku na nejakú inú technológiu / formát, prípadne ste narazili na chybu v článku, nechajte mi spätnú väzbu v komentároch (po registrácií), alebo cez kontaktný formulár.

Použité zdroje

SK Wikipédia: > link <
EN Wikipédia: > link <
ID3v1 - id3.org: > link <
ID3v1.2 - birdcagesoft: > link <
ID3v2.2 - id3.org: > link <
ID3v2.3- id3.org: > link <
ID3v2.4 - id3.org: > link <
ID3v2 Easy - id3.org: > link <

Codeblog
Diskusia

Žiadne príspevky v diskusii.

Nový príspevok

Na prispievanie do diskusie musíte byť prihlásený.