{"id":20056,"date":"2026-09-21T22:29:19","date_gmt":"2026-09-21T20:29:19","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/narzedzia\/gapless-playback-encoder-delay-checker\/"},"modified":"2026-09-21T22:31:05","modified_gmt":"2026-09-21T20:31:05","slug":"gapless-playback-encoder-delay-checker","status":"publish","type":"page","link":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/gapless-playback-encoder-delay-checker\/","title":{"rendered":"Sprawdzenie odtwarzania bez przerw: wyprzedzenie i dope\u0142nienie w MP3, AAC, Opus i FLAC"},"content":{"rendered":"<div class=\"lw-gl\" id=\"gl-wurzel\" style=\"background: var(--bg-panel, #1e1e24); padding: 25px; border-radius: 8px; border: 1px solid var(--border, #2a2a35);\">\n<style>\n.lw-gl .gl-zone { border: 2px dashed var(--border, #2a2a35); border-radius: 8px; padding: 22px; text-align: center; }\n.lw-gl .gl-zone.gl-ueber { border-color: var(--accent, #2ba6df); }\n.lw-gl .gl-kacheln { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin: 16px 0 4px; }\n.lw-gl .gl-kachel { background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); border-radius: 8px; padding: 11px 14px; min-width: 0; }\n.lw-gl .gl-kachel-name { font-size: 0.74rem; color: var(--text-secondary, #a0a0b0); text-transform: uppercase; letter-spacing: 0.4px; }\n.lw-gl .gl-kachel-wert { font-family: monospace; font-size: 1.4rem; font-weight: 700; color: var(--text-primary, #e8e8ee); line-height: 1.25; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.lw-gl .gl-urteil { border-radius: 8px; padding: 12px 15px; margin-top: 14px; border: 1px solid var(--border, #2a2a35); background: var(--bg-body, #14141a); }\n.lw-gl .gl-urteil-kopf { font-weight: 700; color: var(--text-primary, #e8e8ee); margin-bottom: 4px; }\n.lw-gl .gl-ja .gl-urteil-kopf { color: var(--ok, #7ee787); }\n.lw-gl .gl-teils .gl-urteil-kopf { color: var(--gl-warn); }\n.lw-gl .gl-nein .gl-urteil-kopf { color: var(--fehler, #f0857a); }\n.lw-gl { --gl-warn: #e8a33d; }\n:root[data-theme=\"light\"] .lw-gl { --gl-warn: #8f5300; }\n.lw-gl .gl-tabelle { overflow-x: auto; margin-top: 6px; }\n.lw-gl table { border-collapse: collapse; width: 100%; font-size: 0.86rem; }\n.lw-gl th, .lw-gl td { text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--border, #2a2a35); }\n.lw-gl th { color: var(--text-primary, #e8e8ee); white-space: nowrap; }\n.lw-gl td { color: var(--text-primary, #e8e8ee); }\n.lw-gl td.gl-wert { font-family: monospace; color: var(--text-secondary, #a0a0b0); }\n.lw-gl .gl-h { font-weight: 700; color: var(--text-primary, #e8e8ee); font-size: 0.95rem; margin: 24px 0 8px; }\n.lw-gl .gl-klein { font-size: 0.84rem; color: var(--text-secondary, #a0a0b0); line-height: 1.55; }\n.lw-gl .gl-knopf { background: transparent; color: var(--text-secondary, #a0a0b0); border: 1px solid var(--border, #2a2a35); padding: 9px 14px; border-radius: 6px; cursor: pointer; font-size: 0.9rem; margin-top: 14px; }\n.lw-gl .gl-fehler { color: var(--fehler, #f0857a); font-size: 0.88rem; margin-top: 12px; }\n.lw-gl a { color: var(--accent, #2ba6df); }\n@media (max-width: 480px) {\n    .lw-gl .gl-kacheln { grid-template-columns: 1fr 1fr; gap: 8px; }\n    .lw-gl .gl-kachel-wert { font-size: 1.15rem; }\n    .lw-gl th, .lw-gl td { padding: 6px 6px; }\n}\n<\/style>\n<p style=\"color: var(--text-secondary, #a0a0b0); margin-bottom: 18px;\">Kodery stratne dodaj\u0105 pr\u00f3bki na pocz\u0105tku i na ko\u0144cu pliku. Gdy plik podaje, ile ich jest, odtwarzacz usuwa je z powrotem i jeden utw\u00f3r przechodzi w nast\u0119pny bez przerwy. To sprawdzenie odczytuje w\u0142a\u015bnie te deklaracje. Nic nie jest wysy\u0142ane, plik zostaje w przegl\u0105darce.<\/p>\n<div id=\"gl-zone\" class=\"gl-zone\">\n<p style=\"margin: 0 0 12px; color: var(--text-primary, #e8e8ee); font-weight: 700;\">Wyb\u00f3r pliku audio<\/p>\n<p>        <button id=\"gl-knopf\" type=\"button\" class=\"button\" style=\"background: var(--accent, #7ee787); color: var(--on-accent, #0b1114); border: none; padding: 11px 22px; border-radius: 6px; font-weight: 700; cursor: pointer;\">Wyb\u00f3r pliku<\/button><br \/>\n        <input id=\"gl-datei\" type=\"file\" accept=\"audio\/*,.mp3,.m4a,.mp4,.aac,.opus,.ogg,.oga,.flac,.wav,.wave\" hidden><\/p>\n<p class=\"gl-klein\" style=\"margin: 12px 0 0;\">MP3, M4A\/AAC, Opus, Ogg Vorbis, FLAC i WAV. Czytany jest tylko nag\u0142\u00f3wek pliku, nie d\u017awi\u0119k.<\/p>\n<\/p><\/div>\n<div id=\"gl-fehler\" class=\"gl-fehler\" data-mp-mask hidden><\/div>\n<div id=\"gl-ausgabe\" data-mp-mask style=\"margin-top: 18px;\" aria-live=\"polite\" hidden>\n<div id=\"gl-kacheln\" class=\"gl-kacheln\"><\/div>\n<div id=\"gl-urteil\" class=\"gl-urteil\"><\/div>\n<div class=\"gl-h\">Co deklaruje plik<\/div>\n<div class=\"gl-tabelle\">\n<table>\n<thead>\n<tr>\n<th>Pole<\/th>\n<th>Warto\u015b\u0107<\/th>\n<\/tr>\n<\/thead>\n<tbody id=\"gl-felder\"><\/tbody>\n<\/table><\/div>\n<p>        <button id=\"gl-kopieren\" type=\"button\" class=\"gl-knopf\">Kopiowanie wyniku<\/button><br \/>\n        <span id=\"gl-kopiert\" class=\"gl-klein\" style=\"margin-left: 10px;\"><\/span>\n    <\/div>\n<div class=\"gl-h\">Co oznaczaj\u0105 te pola<\/div>\n<p class=\"gl-klein\" style=\"margin: 0 0 6px;\">Kodery oparte na transformacie potrzebuj\u0105 rozbiegu: pierwszy blok wyj\u015bcia opisuje d\u017awi\u0119k le\u017c\u0105cy przed pocz\u0105tkiem pliku, a ostatni si\u0119ga poza jego koniec. Oba ko\u0144ce zostaj\u0105 wi\u0119c wype\u0142nione pr\u00f3bkami, kt\u00f3re nie s\u0105 muzyk\u0105.<\/p>\n<p class=\"gl-klein\" style=\"margin: 0 0 6px;\">MP3 niesie te liczby w ramce Info albo Xing, kt\u00f3r\u0105 zapisuje koder, razem ze swoj\u0105 nazw\u0105. Do podanego tam wyprzedzenia dochodzi op\u00f3\u017anienie samego dekodera; to sprawdzenie dolicza za nie 529 pr\u00f3bek, tyle da\u0142 pomiar do powi\u0105zanego artyku\u0142u.<\/p>\n<p class=\"gl-klein\" style=\"margin: 0 0 6px;\">W MP4 pocz\u0105tek opisuje lista monta\u017cowa, przesuwaj\u0105c start \u015bcie\u017cki. Pole iTunSMPB firmy Apple podaje oba ko\u0144ce w pr\u00f3bkach; gdy go brakuje, tylko czas trwania \u015bcie\u017cki m\u00f3wi odtwarzaczowi, gdzie ma sko\u0144czy\u0107.<\/p>\n<p class=\"gl-klein\" style=\"margin: 0 0 6px;\">Opus podaje swoje wyprzedzenie w nag\u0142\u00f3wku, liczone przy 48 kHz, a ostatnia strona m\u00f3wi, dok\u0105d naprawd\u0119 si\u0119ga d\u017awi\u0119k. RFC 7845 ustala oba, wi\u0119c odtwarzanie bez przerw nie wymaga dodatkowego pola.<\/p>\n<p class=\"gl-klein\" style=\"margin: 0 0 6px;\">FLAC i WAV zapisuj\u0105 dok\u0142adn\u0105 liczb\u0119 pr\u00f3bek, nic wi\u0119c nie jest dodawane i nic nie musi by\u0107 usuwane.<\/p>\n<p class=\"gl-klein\" style=\"margin: 20px 0 0;\">\u0179r\u00f3d\u0142a:<br \/>\n        <a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc7845\" rel=\"noopener\">RFC 7845<\/a> \u00b7<br \/>\n        <a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc9639\" rel=\"noopener\">RFC 9639<\/a> \u00b7<br \/>\n        <a href=\"https:\/\/lame.sourceforge.io\/tech-FAQ.txt\" rel=\"noopener\">LAME tech FAQ<\/a>\n    <\/p>\n<p class=\"gl-klein\" style=\"font-size: 0.8rem; margin: 14px 0 0;\">Czytane s\u0105 tylko nag\u0142\u00f3wki pliku, nie d\u017awi\u0119k. Co konkretny odtwarzacz zrobi z tymi polami, nie jest tu sprawdzane; warto\u015bci pokazuj\u0105, co m\u00f3g\u0142by zrobi\u0107.<\/p>\n<\/div>\n<p><script>\n(function () {\n    'use strict';\n    const T = {\"dezimal\":\",\",\"einleitung\":\"Kodery stratne dodaj\u0105 pr\u00f3bki na pocz\u0105tku i na ko\u0144cu pliku. Gdy plik podaje, ile ich jest, odtwarzacz usuwa je z powrotem i jeden utw\u00f3r przechodzi w nast\u0119pny bez przerwy. To sprawdzenie odczytuje w\u0142a\u015bnie te deklaracje. Nic nie jest wysy\u0142ane, plik zostaje w przegl\u0105darce.\",\"zone_titel\":\"Wyb\u00f3r pliku audio\",\"knopf_datei\":\"Wyb\u00f3r pliku\",\"zone_hinweis\":\"MP3, M4A\\\/AAC, Opus, Ogg Vorbis, FLAC i WAV. Czytany jest tylko nag\u0142\u00f3wek pliku, nie d\u017awi\u0119k.\",\"k_format\":\"Format\",\"k_vorlauf\":\"Wyprzedzenie na pocz\u0105tku\",\"k_nachlauf\":\"Dope\u0142nienie na ko\u0144cu\",\"k_luecke\":\"Przerwa bez tych p\u00f3l\",\"h_angaben\":\"Co deklaruje plik\",\"sp_feld\":\"Pole\",\"sp_wert\":\"Warto\u015b\u0107\",\"f_format\":\"Format\",\"f_rate\":\"Cz\u0119stotliwo\u015b\u0107 pr\u00f3bkowania\",\"f_kanaele\":\"Kana\u0142y\",\"f_rahmen\":\"Ramka Info\",\"f_encoder\":\"Koder\",\"f_vorlauf_roh\":\"Wyprzedzenie w pr\u00f3bkach\",\"f_nachlauf_roh\":\"Dope\u0142nienie w pr\u00f3bkach\",\"f_quellrate\":\"Pierwotna cz\u0119stotliwo\u015b\u0107\",\"f_granule\":\"Ostatnia pozycja granule\",\"f_elst\":\"Lista monta\u017cowa\",\"f_itunsmpb\":\"iTunSMPB\",\"f_tiefe\":\"G\u0142\u0119bia bitowa\",\"f_abtastwerte\":\"Pr\u00f3bki d\u017awi\u0119ku\",\"f_dauer\":\"Czas trwania\",\"format_mp3\":\"MP3\",\"format_mp4\":\"MP4 \\\/ AAC\",\"format_opus\":\"Opus w Ogg\",\"format_vorbis\":\"Ogg Vorbis\",\"format_flac\":\"FLAC\",\"format_wav\":\"WAV\",\"elst_wert\":\"start {start}, czas {dauer}\",\"itunsmpb_wert\":\"{vorlauf} przed, {nachlauf} po\",\"wert_keiner\":\"brak\",\"wert_unbekannt\":\"nieznane\",\"urteil_ja\":\"Bez przerw ju\u017c z samego formatu\",\"urteil_mit_angaben\":\"Bez przerw tylko przy uwzgl\u0119dnieniu p\u00f3l\",\"urteil_teils\":\"Pocz\u0105tek podany, koniec nie\",\"urteil_nein\":\"Brak deklaracji w pliku\",\"urteil_text_ja\":\"Liczba pr\u00f3bek d\u017awi\u0119ku wynika z formatu, wi\u0119c dekoder ko\u0144czy dok\u0142adnie tam, gdzie ko\u0144czy si\u0119 utw\u00f3r. R\u0119czne przycinanie nie jest potrzebne.\",\"urteil_text_mit_angaben\":\"Plik podaje, ile pr\u00f3bek nale\u017cy do kodera, a nie do muzyki. Odtwarzacz czytaj\u0105cy te pola przechodzi z utworu w utw\u00f3r; odtwarzacz je pomijaj\u0105cy wstawia przerw\u0119 podan\u0105 powy\u017cej.\",\"urteil_text_teils\":\"Pocz\u0105tek opisuje lista monta\u017cowa, koniec nie jest opisany osobno. Kto uwzgl\u0119dni tak\u017ce czas trwania \u015bcie\u017cki, i tak trafi we w\u0142a\u015bciw\u0105 d\u0142ugo\u015b\u0107; kto uwzgl\u0119dni tylko pocz\u0105tek, zachowa dope\u0142nienie jako cisz\u0119.\",\"urteil_text_nein\":\"Plik nie zawiera pola na wyprzedzenie ani dope\u0142nienie. Ka\u017cdy odtwarzacz zachowa wi\u0119c pr\u00f3bki dodane przez koder, a mi\u0119dzy dwoma utworami zostanie przerwa co najmniej 25 ms.\",\"bericht_kopf\":\"Sprawdzenie odtwarzania bez przerw\",\"knopf_kopieren\":\"Kopiowanie wyniku\",\"kopiert\":\"skopiowano\",\"kopieren_fehler\":\"kopiowanie niemo\u017cliwe\",\"fehler_format\":\"Ten plik nie nale\u017cy do format\u00f3w czytanych tutaj: MP3, M4A\\\/AAC, Opus, Ogg Vorbis, FLAC ani WAV.\",\"fehler_lesen\":\"Pliku nie da\u0142o si\u0119 odczyta\u0107.\",\"h_erklaerung\":\"Co oznaczaj\u0105 te pola\",\"erkl_grund\":\"Kodery oparte na transformacie potrzebuj\u0105 rozbiegu: pierwszy blok wyj\u015bcia opisuje d\u017awi\u0119k le\u017c\u0105cy przed pocz\u0105tkiem pliku, a ostatni si\u0119ga poza jego koniec. Oba ko\u0144ce zostaj\u0105 wi\u0119c wype\u0142nione pr\u00f3bkami, kt\u00f3re nie s\u0105 muzyk\u0105.\",\"erkl_mp3\":\"MP3 niesie te liczby w ramce Info albo Xing, kt\u00f3r\u0105 zapisuje koder, razem ze swoj\u0105 nazw\u0105. Do podanego tam wyprzedzenia dochodzi op\u00f3\u017anienie samego dekodera; to sprawdzenie dolicza za nie 529 pr\u00f3bek, tyle da\u0142 pomiar do powi\u0105zanego artyku\u0142u.\",\"erkl_aac\":\"W MP4 pocz\u0105tek opisuje lista monta\u017cowa, przesuwaj\u0105c start \u015bcie\u017cki. Pole iTunSMPB firmy Apple podaje oba ko\u0144ce w pr\u00f3bkach; gdy go brakuje, tylko czas trwania \u015bcie\u017cki m\u00f3wi odtwarzaczowi, gdzie ma sko\u0144czy\u0107.\",\"erkl_opus\":\"Opus podaje swoje wyprzedzenie w nag\u0142\u00f3wku, liczone przy 48 kHz, a ostatnia strona m\u00f3wi, dok\u0105d naprawd\u0119 si\u0119ga d\u017awi\u0119k. RFC 7845 ustala oba, wi\u0119c odtwarzanie bez przerw nie wymaga dodatkowego pola.\",\"erkl_flac\":\"FLAC i WAV zapisuj\u0105 dok\u0142adn\u0105 liczb\u0119 pr\u00f3bek, nic wi\u0119c nie jest dodawane i nic nie musi by\u0107 usuwane.\",\"quellen_titel\":\"\u0179r\u00f3d\u0142a\",\"grenze\":\"Czytane s\u0105 tylko nag\u0142\u00f3wki pliku, nie d\u017awi\u0119k. Co konkretny odtwarzacz zrobi z tymi polami, nie jest tu sprawdzane; warto\u015bci pokazuj\u0105, co m\u00f3g\u0142by zrobi\u0107.\"};<\/p>\n<p>    function el(id) { return document.getElementById(id); }\n    function text(schluessel, werte) {\n        var s = T[schluessel] || '';\n        return s.replace(\/\\{(\\w+)\\}\/g, function (_, k) { return werte && werte[k] !== undefined ? werte[k] : ''; });\n    }\n    function zahl(wert, stellen) {\n        if (wert === null || wert === undefined || !isFinite(wert)) { return '\u2013'; }\n        var s = Number(wert).toFixed(stellen === undefined ? 1 : stellen);\n        return T.dezimal === ',' ? s.replace('.', ',') : s;\n    }<\/p>\n<p>    \/\/ ---- kleine Leser ------------------------------------------------------\n    function ascii(dv, pos, laenge) {\n        var s = '';\n        for (var i = 0; i < laenge; i++) {\n            if (pos + i >= dv.byteLength) { break; }\n            s += String.fromCharCode(dv.getUint8(pos + i));\n        }\n        return s;\n    }\n    function suchen(dv, muster, von, bis) {\n        var ende = Math.min(bis === undefined ? dv.byteLength : bis, dv.byteLength) - muster.length;\n        for (var i = Math.max(0, von || 0); i <= ende; i++) {\n            var treffer = true;\n            for (var j = 0; j < muster.length; j++) {\n                if (dv.getUint8(i + j) !== muster.charCodeAt(j)) { treffer = false; break; }\n            }\n            if (treffer) { return i; }\n        }\n        return -1;\n    }\n\n    \/\/ ---- MP3 ---------------------------------------------------------------\n    var MP3_RATEN = [[11025, 12000, 8000], [0, 0, 0], [22050, 24000, 16000], [44100, 48000, 32000]];\n\n    function id3Laenge(dv) {\n        if (dv.byteLength < 10 || ascii(dv, 0, 3) !== 'ID3') { return 0; }\n        var g = 0;\n        for (var i = 6; i < 10; i++) { g = (g << 7) | (dv.getUint8(i) &#038; 0x7F); }\n        return g + 10;\n    }\n\n    function mp3Rahmen(dv, von) {\n        for (var i = von; i < Math.min(dv.byteLength - 4, von + 200000); i++) {\n            if (dv.getUint8(i) !== 0xFF || (dv.getUint8(i + 1) &#038; 0xE0) !== 0xE0) { continue; }\n            var b1 = dv.getUint8(i + 1), b2 = dv.getUint8(i + 2), b3 = dv.getUint8(i + 3);\n            var version = (b1 >> 3) & 3, lage = (b1 >> 1) & 3, rateZeiger = (b2 >> 2) & 3;\n            if (version === 1 || lage === 0 || rateZeiger === 3) { continue; }\n            var rate = MP3_RATEN[version][rateZeiger];\n            if (!rate) { continue; }\n            return { pos: i, rate: rate, version: version, lage: lage, kanaele: ((b3 >> 6) & 3) === 3 ? 1 : 2 };\n        }\n        return null;\n    }<\/p>\n<p>    function mp3Lesen(puffer) {\n        var dv = new DataView(puffer);\n        var start = id3Laenge(dv);\n        var rahmen = mp3Rahmen(dv, start);\n        if (!rahmen) { return null; }\n        var i = -1, art = '';\n        for (var k = 0; k < 2; k++) {\n            var m = k === 0 ? 'Info' : 'Xing';\n            var p = suchen(dv, m, rahmen.pos, rahmen.pos + 1200);\n            if (p >= 0 && (i < 0 || p < i)) { i = p; art = m; }\n        }\n        var ergebnis = { typ: 'mp3', rate: rahmen.rate, kanaele: rahmen.kanaele, rahmen: null,\n                         encoder: null, vorlauf: null, nachlauf: null, abtastwerte: null };\n        if (i < 0) { return ergebnis; }\n        var flaggen = dv.getUint32(i + 4), p2 = i + 8;\n        if (flaggen &#038; 1) { ergebnis.rahmenzahl = dv.getUint32(p2); p2 += 4; }\n        if (flaggen &#038; 2) { p2 += 4; }\n        if (flaggen &#038; 4) { p2 += 100; }\n        if (flaggen &#038; 8) { p2 += 4; }\n        ergebnis.rahmen = art;\n        if (p2 + 24 > dv.byteLength) { return ergebnis; }\n        ergebnis.encoder = ascii(dv, p2, 9).replace(\/[^\\x20-\\x7E]\/g, '');\n        var a = dv.getUint8(p2 + 21), b = dv.getUint8(p2 + 22), c = dv.getUint8(p2 + 23);\n        ergebnis.vorlauf = (a << 4) | (b >> 4);\n        ergebnis.nachlauf = ((b & 0x0F) << 8) | c;\n        if (ergebnis.rahmenzahl) {\n            var jeRahmen = rahmen.version === 3 ? 1152 : 576;\n            ergebnis.abtastwerte = ergebnis.rahmenzahl * jeRahmen - ergebnis.vorlauf - ergebnis.nachlauf;\n        }\n        return ergebnis;\n    }\n\n    \/\/ ---- MP4 \/ M4A ---------------------------------------------------------\n    function mp4Kaesten(dv, von, bis, tiefe, sammeln) {\n        var p = von;\n        while (p + 8 <= bis) {\n            var groesse = dv.getUint32(p), name = ascii(dv, p + 4, 4), inhalt = p + 8;\n            if (groesse === 1) { groesse = dv.getUint32(p + 8) * 4294967296 + dv.getUint32(p + 12); inhalt = p + 16; }\n            if (groesse === 0) { groesse = bis - p; }\n            if (groesse < 8 || p + groesse > bis) { break; }\n            sammeln(name, inhalt, p + groesse);\n            if (tiefe > 0 && \/^(moov|trak|mdia|minf|stbl|edts|udta|meta|ilst|----)$\/.test(name)) {\n                var innen = name === 'meta' ? inhalt + 4 : inhalt;\n                mp4Kaesten(dv, innen, p + groesse, tiefe - 1, sammeln);\n            }\n            p += groesse;\n        }\n    }<\/p>\n<p>    function mp4Lesen(puffer) {\n        var dv = new DataView(puffer);\n        var e = { typ: 'mp4', rate: null, kanaele: null, elst: null, itunsmpb: null, dauer: null, zeitbasis: null };\n        var mdhdRate = null, letzterName = null;\n        mp4Kaesten(dv, 0, dv.byteLength, 6, function (name, von, bis) {\n            if (name === 'mvhd') {\n                var v = dv.getUint8(von);\n                e.zeitbasis = v === 1 ? dv.getUint32(von + 20) : dv.getUint32(von + 12);\n            } else if (name === 'mdhd') {\n                var v2 = dv.getUint8(von);\n                mdhdRate = v2 === 1 ? dv.getUint32(von + 20) : dv.getUint32(von + 12);\n                e.rate = e.rate || mdhdRate;\n                e.abtastwerte = v2 === 1 ? dv.getUint32(von + 28) : dv.getUint32(von + 16);\n            } else if (name === 'elst') {\n                var version = dv.getUint8(von), anzahl = dv.getUint32(von + 4);\n                if (anzahl > 0) {\n                    if (version === 1) {\n                        e.elst = { anzahl: anzahl, dauer: dv.getUint32(von + 12) * 4294967296 + dv.getUint32(von + 16),\n                                   start: dv.getInt32(von + 24) };\n                    } else {\n                        e.elst = { anzahl: anzahl, dauer: dv.getUint32(von + 8), start: dv.getInt32(von + 12) };\n                    }\n                }\n            } else if (name === 'mp4a') {\n                e.kanaele = dv.getUint16(von + 16);\n                e.rate = dv.getUint16(von + 24);\n            } else if (name === 'name') {\n                letzterName = ascii(dv, von + 4, bis - von - 4);\n            } else if (name === 'data' && letzterName && \/iTunSMPB\/.test(letzterName)) {\n                var roh = ascii(dv, von + 8, Math.min(120, bis - von - 8));\n                var zahlen = roh.match(\/[0-9A-Fa-f]{8,16}\/g) || [];\n                if (zahlen.length >= 4) {\n                    e.itunsmpb = { vorlauf: parseInt(zahlen[1], 16), nachlauf: parseInt(zahlen[2], 16),\n                                   abtastwerte: parseInt(zahlen[3], 16) };\n                }\n                letzterName = null;\n            }\n        });\n        return e;\n    }<\/p>\n<p>    \/\/ ---- Ogg: Opus und Vorbis ----------------------------------------------\n    function letzteGranule(dv) {\n        for (var i = dv.byteLength - 14; i >= 0 && i > dv.byteLength - 70000; i--) {\n            if (ascii(dv, i, 4) === 'OggS') {\n                var lo = dv.getUint32(i + 6, true), hi = dv.getUint32(i + 10, true);\n                return hi * 4294967296 + lo;\n            }\n        }\n        return null;\n    }<\/p>\n<p>    function oggLesen(puffer) {\n        var dv = new DataView(puffer);\n        var o = suchen(dv, 'OpusHead', 0, 65536);\n        if (o >= 0) {\n            return { typ: 'opus', kanaele: dv.getUint8(o + 9), vorlauf: dv.getUint16(o + 10, true),\n                     quellrate: dv.getUint32(o + 12, true), rate: 48000, granule: letzteGranule(dv) };\n        }\n        var v = suchen(dv, '\\x01vorbis', 0, 65536);\n        if (v >= 0) {\n            return { typ: 'vorbis', kanaele: dv.getUint8(v + 11), rate: dv.getUint32(v + 12, true),\n                     granule: letzteGranule(dv) };\n        }\n        return null;\n    }<\/p>\n<p>    \/\/ ---- FLAC und WAV ------------------------------------------------------\n    function flacLesen(puffer) {\n        var dv = new DataView(puffer);\n        if (ascii(dv, 0, 4) !== 'fLaC' || dv.byteLength < 42) { return null; }\n        var p = 8;                                    \/\/ 4 Kennung + 4 Blockkopf\n        var rate = (dv.getUint8(p + 10) << 12) | (dv.getUint8(p + 11) << 4) | (dv.getUint8(p + 12) >> 4);\n        var kanaele = ((dv.getUint8(p + 12) >> 1) & 7) + 1;\n        var tiefe = (((dv.getUint8(p + 12) & 1) << 4) | (dv.getUint8(p + 13) >> 4)) + 1;\n        var hoch = dv.getUint8(p + 13) & 0x0F;\n        var abtastwerte = hoch * 4294967296 + dv.getUint32(p + 14);\n        return { typ: 'flac', rate: rate, kanaele: kanaele, tiefe: tiefe, abtastwerte: abtastwerte };\n    }<\/p>\n<p>    function wavLesen(puffer) {\n        var dv = new DataView(puffer);\n        if (ascii(dv, 0, 4) !== 'RIFF' || ascii(dv, 8, 4) !== 'WAVE') { return null; }\n        var p = 12, rate = null, kanaele = null, tiefe = null, datenlaenge = null, block = null;\n        while (p + 8 <= dv.byteLength) {\n            var kennung = ascii(dv, p, 4), laenge = dv.getUint32(p + 4, true);\n            if (kennung === 'fmt ') {\n                kanaele = dv.getUint16(p + 10, true);\n                rate = dv.getUint32(p + 12, true);\n                block = dv.getUint16(p + 20, true);\n                tiefe = dv.getUint16(p + 22, true);\n            } else if (kennung === 'data') {\n                datenlaenge = Math.min(laenge, dv.byteLength - p - 8);\n            }\n            p += 8 + laenge + (laenge &#038; 1);\n        }\n        if (!rate) { return null; }\n        return { typ: 'wav', rate: rate, kanaele: kanaele, tiefe: tiefe,\n                 abtastwerte: block ? Math.floor(datenlaenge \/ block) : null };\n    }\n\n    function erkennen(puffer) {\n        var dv = new DataView(puffer);\n        if (dv.byteLength < 16) { return null; }\n        if (ascii(dv, 0, 4) === 'RIFF') { return wavLesen(puffer); }\n        if (ascii(dv, 0, 4) === 'fLaC') { return flacLesen(puffer); }\n        if (ascii(dv, 0, 4) === 'OggS') { return oggLesen(puffer); }\n        if (ascii(dv, 4, 4) === 'ftyp') { return mp4Lesen(puffer); }\n        if (ascii(dv, 0, 3) === 'ID3' || (dv.getUint8(0) === 0xFF &#038;&#038; (dv.getUint8(1) &#038; 0xE0) === 0xE0)) {\n            return mp3Lesen(puffer);\n        }\n        return null;\n    }\n\n    \/\/ ---- Auswertung --------------------------------------------------------\n    var DECODER_MP3 = 529;        \/\/ gemessene Verzoegerung der Decoder, siehe Text\n\n    function auswerten(info) {\n        if (!info) { return null; }\n        var rate = info.rate || 44100;\n        var a = { typ: info.typ, rate: rate, kanaele: info.kanaele || null,\n                  vorlauf: null, nachlauf: null, luecke_ms: null, urteil: 'nein', abtastwerte: info.abtastwerte || null };\n        if (info.typ === 'wav' || info.typ === 'flac') {\n            a.vorlauf = 0; a.nachlauf = 0; a.luecke_ms = 0; a.urteil = 'ja';\n        } else if (info.typ === 'mp3') {\n            if (info.vorlauf === null || info.vorlauf === undefined) {\n                a.urteil = 'nein';\n            } else {\n                a.vorlauf = info.vorlauf + DECODER_MP3;\n                a.nachlauf = info.nachlauf;\n                a.luecke_ms = (a.vorlauf + a.nachlauf) \/ rate * 1000;\n                a.urteil = 'mit_angaben';\n            }\n        } else if (info.typ === 'opus') {\n            a.vorlauf = info.vorlauf;\n            a.nachlauf = null;\n            a.luecke_ms = info.vorlauf \/ 48000 * 1000;\n            a.urteil = 'ja';\n            if (info.granule !== null &#038;&#038; info.granule !== undefined) {\n                a.abtastwerte = Math.max(0, info.granule - info.vorlauf);\n            }\n        } else if (info.typ === 'vorbis') {\n            a.vorlauf = 0; a.nachlauf = 0; a.luecke_ms = 0; a.urteil = 'ja';\n            if (info.granule) { a.abtastwerte = info.granule; }\n        } else if (info.typ === 'mp4') {\n            var vor = null, nach = null;\n            if (info.itunsmpb) { vor = info.itunsmpb.vorlauf; nach = info.itunsmpb.nachlauf; }\n            else if (info.elst &#038;&#038; info.elst.start > 0) { vor = info.elst.start; }\n            a.vorlauf = vor;\n            a.nachlauf = nach;\n            if (vor !== null) {\n                a.luecke_ms = (vor + (nach || 0)) \/ rate * 1000;\n                a.urteil = info.itunsmpb ? 'mit_angaben' : 'teils';\n            } else {\n                a.urteil = 'nein';\n            }\n        }\n        return a;\n    }<\/p>\n<p>    function felder(info, a) {\n        var liste = [];\n        function f(name, wert) { if (wert !== null && wert !== undefined && wert !== '') { liste.push([name, String(wert)]); } }\n        f(T.f_format, T['format_' + info.typ] || info.typ);\n        f(T.f_rate, (info.rate || a.rate) + ' Hz');\n        f(T.f_kanaele, info.kanaele);\n        if (info.typ === 'mp3') {\n            f(T.f_rahmen, info.rahmen || T.wert_keiner);\n            f(T.f_encoder, info.encoder);\n            f(T.f_vorlauf_roh, info.vorlauf === null ? T.wert_keiner : info.vorlauf + ' + ' + DECODER_MP3);\n            f(T.f_nachlauf_roh, info.nachlauf === null ? T.wert_keiner : info.nachlauf);\n        } else if (info.typ === 'opus') {\n            f(T.f_vorlauf_roh, info.vorlauf);\n            f(T.f_quellrate, info.quellrate ? info.quellrate + ' Hz' : null);\n            f(T.f_granule, info.granule);\n        } else if (info.typ === 'mp4') {\n            f(T.f_elst, info.elst ? text('elst_wert', { start: info.elst.start, dauer: info.elst.dauer }) : T.wert_keiner);\n            f(T.f_itunsmpb, info.itunsmpb ? text('itunsmpb_wert', { vorlauf: info.itunsmpb.vorlauf, nachlauf: info.itunsmpb.nachlauf }) : T.wert_keiner);\n        } else if (info.typ === 'flac') {\n            f(T.f_tiefe, info.tiefe ? info.tiefe + ' Bit' : null);\n        } else if (info.typ === 'vorbis') {\n            f(T.f_granule, info.granule);\n        } else if (info.typ === 'wav') {\n            f(T.f_tiefe, info.tiefe ? info.tiefe + ' Bit' : null);\n        }\n        if (a.abtastwerte) {\n            f(T.f_abtastwerte, a.abtastwerte);\n            f(T.f_dauer, zahl(a.abtastwerte \/ (a.rate || 44100), 3) + ' s');\n        }\n        return liste;\n    }<\/p>\n<p>    function bericht(info, a) {\n        var zeilen = [T.bericht_kopf];\n        felder(info, a).forEach(function (z) { zeilen.push(z[0] + ': ' + z[1]); });\n        zeilen.push(T.k_luecke + ': ' + (a.luecke_ms === null ? T.wert_unbekannt : zahl(a.luecke_ms, 1) + ' ms'));\n        zeilen.push(T['urteil_' + a.urteil]);\n        return zeilen.join('\\n');\n    }<\/p>\n<p>    \/\/ ---- Darstellung -------------------------------------------------------\n    function kachel(name, wert) {\n        var d = document.createElement('div');\n        d.className = 'gl-kachel';\n        var n = document.createElement('div'); n.className = 'gl-kachel-name'; n.textContent = name;\n        var w = document.createElement('div'); w.className = 'gl-kachel-wert'; w.textContent = wert;\n        d.appendChild(n); d.appendChild(w);\n        return d;\n    }<\/p>\n<p>    function darstellen(info, a) {\n        var kacheln = el('gl-kacheln'), urteil = el('gl-urteil'), tab = el('gl-felder');\n        if (!kacheln) { return; }\n        kacheln.textContent = '';\n        kacheln.appendChild(kachel(T.k_format, T['format_' + info.typ] || info.typ));\n        kacheln.appendChild(kachel(T.k_vorlauf, a.vorlauf === null ? T.wert_unbekannt : zahl(a.vorlauf \/ (a.rate || 44100) * 1000, 1) + ' ms'));\n        kacheln.appendChild(kachel(T.k_nachlauf, a.nachlauf === null ? T.wert_unbekannt : zahl(a.nachlauf \/ (a.rate || 44100) * 1000, 1) + ' ms'));\n        kacheln.appendChild(kachel(T.k_luecke, a.luecke_ms === null ? T.wert_unbekannt : zahl(a.luecke_ms, 1) + ' ms'));<\/p>\n<p>        urteil.className = 'gl-urteil gl-' + (a.urteil === 'mit_angaben' ? 'teils' : a.urteil);\n        urteil.textContent = '';\n        var kopf = document.createElement('div');\n        kopf.className = 'gl-urteil-kopf';\n        kopf.textContent = T['urteil_' + a.urteil];\n        var txt = document.createElement('div');\n        txt.className = 'gl-klein';\n        txt.textContent = T['urteil_text_' + a.urteil];\n        urteil.appendChild(kopf); urteil.appendChild(txt);<\/p>\n<p>        tab.textContent = '';\n        felder(info, a).forEach(function (z) {\n            var tr = document.createElement('tr');\n            var td1 = document.createElement('td'); td1.textContent = z[0];\n            var td2 = document.createElement('td'); td2.className = 'gl-wert'; td2.textContent = z[1];\n            tr.appendChild(td1); tr.appendChild(td2);\n            tab.appendChild(tr);\n        });\n        el('gl-ausgabe').hidden = false;\n        el('gl-fehler').hidden = true;\n        return a;\n    }<\/p>\n<p>    function fehlerZeigen(s) {\n        var f = el('gl-fehler');\n        if (!f) { return; }\n        f.textContent = s;\n        f.hidden = false;\n        el('gl-ausgabe').hidden = true;\n    }<\/p>\n<p>    var letztes = null;\n    function verarbeiten(puffer) {\n        var info;\n        try { info = erkennen(puffer); } catch (x) { info = null; }\n        if (!info) { fehlerZeigen(T.fehler_format); return null; }\n        var a = auswerten(info);\n        letztes = { info: info, a: a };\n        return darstellen(info, a);\n    }<\/p>\n<p>    function dateiNehmen(datei) {\n        if (!datei) { return; }\n        var leser = new FileReader();\n        leser.onload = function () { verarbeiten(leser.result); };\n        leser.onerror = function () { fehlerZeigen(T.fehler_lesen); };\n        try { leser.readAsArrayBuffer(datei); } catch (x) { fehlerZeigen(T.fehler_lesen); }\n    }<\/p>\n<p>    window.LW_TEST = window.LW_TEST || {};\n    window.LW_TEST.GL = {\n        T: T, erkennen: erkennen, mp3Lesen: mp3Lesen, mp4Lesen: mp4Lesen, oggLesen: oggLesen,\n        flacLesen: flacLesen, wavLesen: wavLesen, auswerten: auswerten, felder: felder,\n        bericht: bericht, darstellen: darstellen, verarbeiten: verarbeiten, zahl: zahl,\n        DECODER_MP3: DECODER_MP3\n    };<\/p>\n<p>    var zone = el('gl-zone'), eingabe = el('gl-datei'), knopf = el('gl-knopf');\n    if (!zone || !eingabe || !knopf) { return; }\n    knopf.addEventListener('click', function () { eingabe.click(); });\n    eingabe.addEventListener('change', function () { dateiNehmen(eingabe.files && eingabe.files[0]); eingabe.value = ''; });\n    ['dragenter', 'dragover'].forEach(function (typ) {\n        zone.addEventListener(typ, function (ev) { ev.preventDefault(); zone.classList.add('gl-ueber'); });\n    });\n    ['dragleave', 'drop'].forEach(function (typ) {\n        zone.addEventListener(typ, function (ev) { ev.preventDefault(); zone.classList.remove('gl-ueber'); });\n    });\n    zone.addEventListener('drop', function (ev) {\n        ev.preventDefault();\n        dateiNehmen(ev.dataTransfer && ev.dataTransfer.files && ev.dataTransfer.files[0]);\n    });\n    var kopieren = el('gl-kopieren'), kopiert = el('gl-kopiert');\n    if (kopieren) {\n        kopieren.addEventListener('click', function () {\n            if (!letztes) { return; }\n            var t = bericht(letztes.info, letztes.a);\n            if (navigator.clipboard && navigator.clipboard.writeText) {\n                navigator.clipboard.writeText(t).then(function () { kopiert.textContent = T.kopiert; },\n                    function () { kopiert.textContent = T.kopieren_fehler; });\n            } else {\n                kopiert.textContent = T.kopieren_fehler;\n            }\n        });\n    }\n})();\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Czyta plik audio w przegl\u0105darce i podaje, co sam plik deklaruje o wyprzedzeniu i dope\u0142nieniu: ramka LAME w MP3, lista monta\u017cowa i iTunSMPB w MP4, pre-skip w Opusie, liczba pr\u00f3bek w FLAC. Do tego d\u0142ugo\u015b\u0107 przerwy, kt\u00f3r\u0105 wstawi odtwarzacz pomijaj\u0105cy te pola.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":9284,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"template-tool-base.php","meta":{"footnotes":""},"tags":[92906],"class_list":["post-20056","page","type-page","status-publish","hentry","tag-music-production-pl"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Sprawdzenie odtwarzania bez przerw: wyprzedzenie i dope\u0142nienie w MP3, AAC, Opus i FLAC - Lukas Wojcik - Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/gapless-playback-encoder-delay-checker\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Sprawdzenie odtwarzania bez przerw: wyprzedzenie i dope\u0142nienie w MP3, AAC, Opus i FLAC - Lukas Wojcik - Blog\" \/>\n<meta property=\"og:description\" content=\"Czyta plik audio w przegl\u0105darce i podaje, co sam plik deklaruje o wyprzedzeniu i dope\u0142nieniu: ramka LAME w MP3, lista monta\u017cowa i iTunSMPB w MP4, pre-skip w Opusie, liczba pr\u00f3bek w FLAC. Do tego d\u0142ugo\u015b\u0107 przerwy, kt\u00f3r\u0105 wstawi odtwarzacz pomijaj\u0105cy te pola.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/gapless-playback-encoder-delay-checker\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"article:modified_time\" content=\"2026-09-21T20:31:05+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"2 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/gapless-playback-encoder-delay-checker\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/gapless-playback-encoder-delay-checker\\\/\",\"name\":\"Sprawdzenie odtwarzania bez przerw: wyprzedzenie i dope\u0142nienie w MP3, AAC, Opus i FLAC - Lukas Wojcik - Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"datePublished\":\"2026-09-21T20:29:19+00:00\",\"dateModified\":\"2026-09-21T20:31:05+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/gapless-playback-encoder-delay-checker\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/gapless-playback-encoder-delay-checker\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/gapless-playback-encoder-delay-checker\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Toolbox\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/toolbox-3\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Sprawdzenie odtwarzania bez przerw: wyprzedzenie i dope\u0142nienie w MP3, AAC, Opus i FLAC\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\",\"name\":\"Lukas Wojcik - Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\",\"name\":\"Lukas Wojcik\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"width\":424,\"height\":636,\"caption\":\"Lukas Wojcik\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Sprawdzenie odtwarzania bez przerw: wyprzedzenie i dope\u0142nienie w MP3, AAC, Opus i FLAC - Lukas Wojcik - Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/gapless-playback-encoder-delay-checker\/","og_locale":"en_US","og_type":"article","og_title":"Sprawdzenie odtwarzania bez przerw: wyprzedzenie i dope\u0142nienie w MP3, AAC, Opus i FLAC - Lukas Wojcik - Blog","og_description":"Czyta plik audio w przegl\u0105darce i podaje, co sam plik deklaruje o wyprzedzeniu i dope\u0142nieniu: ramka LAME w MP3, lista monta\u017cowa i iTunSMPB w MP4, pre-skip w Opusie, liczba pr\u00f3bek w FLAC. Do tego d\u0142ugo\u015b\u0107 przerwy, kt\u00f3r\u0105 wstawi odtwarzacz pomijaj\u0105cy te pola.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/gapless-playback-encoder-delay-checker\/","og_site_name":"Lukas Wojcik - Blog","article_modified_time":"2026-09-21T20:31:05+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg","type":"image\/jpeg"}],"twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"2 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/gapless-playback-encoder-delay-checker\/","url":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/gapless-playback-encoder-delay-checker\/","name":"Sprawdzenie odtwarzania bez przerw: wyprzedzenie i dope\u0142nienie w MP3, AAC, Opus i FLAC - Lukas Wojcik - Blog","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"datePublished":"2026-09-21T20:29:19+00:00","dateModified":"2026-09-21T20:31:05+00:00","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/gapless-playback-encoder-delay-checker\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/gapless-playback-encoder-delay-checker\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/gapless-playback-encoder-delay-checker\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Toolbox","item":"https:\/\/www.lukaswojcik.com\/blog\/toolbox-3\/"},{"@type":"ListItem","position":3,"name":"Sprawdzenie odtwarzania bez przerw: wyprzedzenie i dope\u0142nienie w MP3, AAC, Opus i FLAC"}]},{"@type":"WebSite","@id":"https:\/\/www.lukaswojcik.com\/blog\/#website","url":"https:\/\/www.lukaswojcik.com\/blog\/","name":"Lukas Wojcik - Blog","description":"","publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lukaswojcik.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9","name":"Lukas Wojcik","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","width":424,"height":636,"caption":"Lukas Wojcik"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"]}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/20056","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/comments?post=20056"}],"version-history":[{"count":1,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/20056\/revisions"}],"predecessor-version":[{"id":20059,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/20056\/revisions\/20059"}],"up":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/9284"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=20056"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=20056"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}