Maîtriser l'analyse des en-têtes FLV : du format binaire aux métadonnées

Anatomie du format FLV

Le format FLV (Flash Video) structure ses données en blocs séquentiels : un en-tête suivi d'une série de tags. L'implémentation dans la bibliothèque flv.js, via le module src/demux/flv-demuxer.js, repose sur la classe FLVDemuxer pour effectuer cette analyse.

Structure de l'en-tête binaire

Les neuf premiers octets d'un fichier FLV forment l'en-tête, définissant les métadonnées fondamentales du fichier.

Décalage Champ Taille Description
0-2 Signature 3 octets Identifiant de fichier, toujours "FLV" (hexadécimal : 0x46, 0x4C, 0x56)
3 Version 1 octet Numéro de version du format, couramment 0x01
4 Drapeaux 1 octet Indicateurs : le bit 0 signale la présence de vidéo, le bit 2 signale la présence d'audio
5-8 OffsetDonnées 4 octets Taille de l'en-tête (généralement 9 octets)

Vérification de conformité du fichier

La fonction verifierFormat valide l'en-tête et extrait les informations initiales.

static verifierFormat(tampon) {
    let octets = new Uint8Array(tampon);
    // Vérification de la signature et de la version
    let signatureValide = (octets[0] === 0x46) && (octets[1] === 0x4C) && (octets[2] === 0x56) && (octets[3] === 0x01);
    if (!signatureValide) {
        return { correspondance: false };
    }
    // Décodage des drapeaux de présence des pistes
    let presenceAudio = ((octets[4] >> 2) & 1) === 1;
    let presenceVideo = (octets[4] & 1) === 1;
    // Lecture de l'offset des données (Big-Endian)
    let offsetDonnees = (octets[5] << 24) | (octets[6] << 16) | (octets[7] << 8) | octets[8];
    return {
        correspondance: true,
        pisteAudio: presenceAudio,
        pisteVideo: presenceVideo,
        offsetDonnees: offsetDonnees
    };
}

Flux d'analyse des données

L'analyse des blocs de données (chunks) qui suivent l'en-tête est orchestrée en plusieurs étapes : validation, découpage en tags, et aiguillage vers les parseusr spécifiques. La méthode traiterBlocsDonnees est le point d'entrée principal pour ce processus.

Analyse des tags FLV

Chaque tag est précédé d'un champ PreviousTagSize0 et contient des métadonnées temporelles et structurelles. L'extraction de ces données est essentielle.

traiterBlocsDonnees(bloc, positionDepart) {
    // Gestion du premier bloc
    if (this._premiereAnalyse) {
        this._premiereAnalyse = false;
        let vue = new DataView(bloc, this._positionCourante);
        let tailleTagPrecedent = vue.getUint32(0);
        if (tailleTagPrecedent !== 0) {
            console.warn('En-tête attendu incorrect : PreviousTagSize0 != 0');
        }
        this._positionCourante += 4;
    }

    // Boucle de lecture des tags
    while (this._positionCourante < bloc.byteLength) {
        let vue = new DataView(bloc, this._positionCourante);
        let typeTag = vue.getUint8(0);
        let tailleDonnees = vue.getUint32(1) & 0x00FFFFFF; // Masquage sur 24 bits

        // Reconstruction du timestamp (32 bits en big-endian)
        let timeStamp = (vue.getUint8(7) << 24) | (vue.getUint8(6) << 16) | (vue.getUint8(5) << 8) | vue.getUint8(4);
        let offsetData = this._positionCourante + 11;

        // Aiguillage selon le type de tag
        switch (typeTag) {
            case 0x08: // Audio
                this._analyserDonneesAudio(bloc, offsetData, tailleDonnees, timeStamp);
                break;
            case 0x09: // Vidéo
                this._analyserDonneesVideo(bloc, offsetData, tailleDonnees, timeStamp);
                break;
            case 0x12: // Données de script (métadonnées)
                this._analyserDonneesScript(bloc, offsetData, tailleDonnees);
                break;
        }

        // Avancer la position courante : 11 octets d'en-tête + taille des données + 4 octets de taille du tag précédent
        this._positionCourante += 11 + tailleDonnees + 4;
    }
}

Extraction des métadonnées

Les tags de type script (0x12) contiennent souvent un objet onMetaData décrivant les propriétés du média. L'analyse de ces données permet de configurer le lecteur.

Structure de onMetaData

La méthode _extraireMetadonnees interprète les données du script et peuple une structure d'informations média standardisée.

_extraireMetadonnees(tampon, debutDonnees, taille) {
    let objetScript = AMF.analyserDonneesScript(tampon, debutDonnees, taille);
    
    if (objetScript && objetScript.onMetaData) {
        let meta = objetScript.onMetaData;
        this._infosMedia = {
            dimensions: { largeur: meta.width, hauteur: meta.height },
            dureeTotale: Math.round((meta.duration || 0) * 1000),
            cadence: meta.framerate,
            codecs: {
                audio: this._determinerCodecAudio(meta),
                video: this._determinerCodecVideo(meta)
            },
            debits: {
                audio: meta.audiodatarate,
                video: meta.videodatarate
            }
        };

        // Gestion de l'index des images clés si présent
        if (meta.keyframes && typeof meta.keyframes === 'object') {
            this._infosMedia.indexImagesCles = this._construireIndexImagesCles(meta.keyframes);
        }
    }
}

Les informations extraites sont cruciales pour des fonctionnalités comme l'affichage des métadonnées, la génération de barres de progression précises, la sélection de flux adaptatifs et l'initialisation du lecteur.

Problématiques courantes et diagnostics

L'analyse de fichiers FLV peut présenter divers défis techniques.

Codecs non supportés

Le logiciel peut rejeter des fichiers utilisant des codecs non implémentés.

// Exemple de vérification du codec audio
if (identifiantCodec !== 2 && identifiantCodec !== 10) { // Support limité à MP3 et AAC
    throw new Error(`Codec audio non pris en charge: ID ${identifiantCodec}`);
}

Pistes de résolution : Conversion du fichier vers un codec supporté ou extension des capacités du parseur.

Incohérences temporelles

Un décodage incorrect des timestamps entraîne une désynchronisation audio-vidéo. La reconstruction précise de la valeur à partir des quatre octets épars est fondamentale.

// Exemple de reconstruction complexe d'un timestamp
let valeurTemporelle = ((octet[3] & 0x7F) << 24) | (octet[2] << 16) | (octet[1] << 8) | octet[0];

Pistes de résolution : Vérification de l'outil de génération du fichier et application d'un décalage via une base de temps (timestampBase).

Métadonnées manquantes

Certains fichiers FLV peuvent ne pas contenir de tag onMetaData valide. Il faut alors se rabattre sur l'analyse des premières trames pour déduire les paramètres essentiels comme les codecs et les dimensions.

Maîtriser l'analyse des en-têtes et des métadonnées FLV fournit les fondations nécessaires pour construire des applications web multimédia robustes, capables de gérer le streaming adaptatif, la synchronisation précise des flux et le débogage de fichiers corrompus.

Étiquettes: flv.js FLV analyse binaire ActionScript Message Format métadonnées média

Publié le 21 juillet à 22h28