Živě.cz o počítačích a internetu

Tipy a triky v Delphi, díl 57. - Soubory MPEG

Jan Šindelář - 11.9.2002

Soubory MPEG

Podobně jako v minulém díle, vytvoříme si nejprve základní struktury, které budou soubor MPEG (či přesněji jeho hlavičku) popisovat. Na rozdíl od minule, kdy jsme se zabývali ID3 popiskem a informace jsme prakticky rovnou načítali ze souboru, musíme si v tomto případě nejprve nadefinovat řadu konstant. Ty budou obsahovat jednak příslušné frekvence, datové toky a další informace, které jsou standardní a předem definované a každý soubor se dá zařadit do jedné z kolonek. Tyto konstanty tedy mohou vypadat například takto:

const
  MPEG_version: array[0..2] of string = (`2`, `1`, `2.5`);
  MPEG_layer: array[0..3] of string = (`neznámý`, `I`, `II`, `III`);
  MPEG_protection: array[0..1] of string = (`Ano`, `Ne`);
  MPEG_frequencies: array[0..2, 0..3] of word = ((22050,24000,16000,0), (44100,48000,32000,0), (11025,12000,8000,0));
  MPEG_bitrates: array[0..2,0..2,0..15] of word=
                  (((0,32,48,46,64,80,96,112,128,144,160,176,192,224,256,0),
                    (0, 8,46,24,32,40,48, 56, 64, 80, 96,112,128,144,160,0),
                    (0, 8,16,24,32,40,48, 56, 64, 80, 96,112,128,144,160,0)),

                  ((0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0),
                    (0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,0),
                    (0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,0)),

                  ((0,32,48,46,64,80,96,112,128,144,160,176,192,224,256,0),
                    (0, 8,46,24,32,40,48, 56, 64, 80, 96,112,128,144,160,0),
                    (0, 8,16,24,32,40,48, 56, 64, 80, 96,112,128,144,160,0)));

  MPEG_padding: array[0..1] of string = (`All bits in frame are used`, `Unused bits are filled`);

  MPEG_extension: array[0..1] of string = (`Ne`,`Ano`);

  MPEG_channel: array[0..3] of string = (`Stereo`, `Joint stereo`, `Dual channel`, `Mono`);

  MPEG_modeext: array[0..3,0..3] of word =
                  ((4,8,12,16),
                  (4,8,12,16),
                  (0,4,8,16),
                  (0,0,0,0));

  MPEG_copyright: array[0..1] of string = (`Ne`,`Ano`);

  MPEG_original: array[0..1] of string = (`Ne`,`Ano`);

  MPEG_emphasis: array[0..3] of string = (`None`,`50/15 microseconds`,`Unknown`,`CITT j.17`);

Nyní je třeba si nadefinovat strukturu pro vlastní hlavičku MPEG souboru a její typ, kterou lze popsat kupříkladu takovýmto záznamem:

MPEG_header = record
                  version,
                  layer,
                  protect,
                  bitrate,
                  samplerate,
                  padding,
                  extension,
                  channelmode,
                  modeextension,
                  copyright,
                  original,
                  emphasis:byte;
                end;

  header_type = array[0..3] of byte;

A teď již zbývá jen informace z jednotlivých souborů MP3 načíst do předem připravených struktur, zařadit je podle definovaných konstant do příslušné kategorie, zpracovat a výsledek zobrazit. Abychom si náš příklad usnadnili, použijeme pro celé rozhraní procházení disků, složek a souborů komponenty ze záložky Win 3.1, konkrétně tedy komponenty DriveComboBox, DirectoryListBox a FileListBox. Ty navzájem "propojíme" v Object Inspectoru jejich vlastnostmi tak, jak je běžně zvykem, tedy aby se změna v jedné komponentě interaktivně projevila i v komponentách ostatních.

Pro výpis informací o souboru použijeme podobně jako minule opět komponentu Memo, takže i tu je třeba umístit na formulář.

Samotné zpracování načtených informací a jejich zobrazení budeme provádět v události OnClick komponenty FileListBox.

procedure TForm1.FileListBox1Click(Sender: TObject);
var
  soubor: MPEG_Header;
  f: file;
  hlavicka: header_type;

begin
  try
    Assignfile(f, Filelistbox1.Filename);
    Reset(f, 1);
    blockread(f, hlavicka, SizeOf(hlavicka));
    if not (hlavicka[0] <> 255) or ((hlavicka[1] or $1F) <> 255) then
      begin
        if ((hlavicka[1] and 16) shr 4) = 0 then soubor.version := 2
        else soubor.version := (hlavicka[1] and 8) shr 3;
        soubor.layer := 4 - ((hlavicka[1] and 6) shr 1);
        soubor.protect := hlavicka[1] and 1;
        soubor.bitrate := (hlavicka[2] and 240) shr 4;
        soubor.samplerate := (hlavicka[2] and 12) shr 2;
        soubor.padding := (hlavicka[2] and 2) shr 1;
        soubor.extension := (hlavicka[2] and 1);
        soubor.channelmode := (hlavicka[3] and 192) shr 6;
        soubor.modeextension := (hlavicka[3] and 48) shr 4;
        soubor.copyright := (hlavicka[3] and 8) shr 3;
        soubor.original := (hlavicka[3] and 4) shr 2;
        soubor.emphasis := (hlavicka[3] and 3);

        Memo1.Clear;
        Memo1.Lines.Add(`MPEG ` + MPEG_version[soubor.version] + ` Layer ` + MPEG_layer[soubor.layer]);
        Memo1.Lines.Add(IntToStr(MPEG_bitrates[soubor.version, soubor.layer-1, soubor.bitrate]) + ` kbps`);
        Memo1.Lines.Add(IntToStr(MPEG_frequencies[soubor.version, soubor.samplerate]) + ` Hz`);
        Memo1.Lines.Add(MPEG_channel[soubor.channelmode]);
        Memo1.Lines.Add(`Private : ` + MPEG_extension[soubor.extension]);
        Memo1.Lines.Add(`CRCs : ` + MPEG_protection[soubor.protect]);
        Memo1.Lines.Add(`Copyrighted : ` + MPEG_copyright[soubor.copyright]);
        Memo1.Lines.Add(`Original : ` + MPEG_original[soubor.original]);
        Memo1.Lines.Add(`Emphasis : ` + MPEG_emphasis[soubor.emphasis]);
      end
    else Memo1.Lines.Add(`Chyba !!!!!`);
  except
  end;
end;

Toto je tedy zhruba základ toho, co lze ze souboru MPEG vyčíst a co je asi pro běžného uživatele nejdůležitější. Pokud by vás zajímaly další informace, které se dají z MPEG souboru "vyždímat", odkáži vás pouze na internet jako zdroj informací. Nebudu vás směrovat na konkrétní stránku, aby to nedopadlo jako minule, ale tentokrát již třeba v době čtení tohoto článku bude http://www.id3.org/ fungovat, takže to zkuste například tam.