Les vecteurs de mouvement en H.264
Pour encoder les P-frames et B-frames, H.264 découpe chaque frame en macroblocks (16×16 pixels) et cherche pour chacun la position la plus similaire dans la frame de référence. Cette correspondance est encodée sous forme d'un vecteur (Δx, Δy) — le motion vector.
Une frame 1080p comporte 8 100 macroblocks. Chaque macroblock a un vecteur (Δx, Δy) avec une précision au quart de pixel — soit une plage de valeurs de -512 à +511 par composante. Ces vecteurs sont stockés explicitement dans le flux bitstream H.264.
H.264 — Structure d'une P-frame :
Frame 1080p = 1920×1080 pixels
→ 120 × 67.5 ≈ 8 100 macroblocks 16×16
Pour chaque macroblock dans la P-frame :
motion_vector = (Δx, Δy)
Δx ∈ [-512, +511] (en quarts de pixel)
Δy ∈ [-512, +511] (en quarts de pixel)
Encodage dans le bitstream :
<macroblock_header>
mv_x = Δx ← valeur entière stockée
mv_y = Δy ← valeur entière stockée
</macroblock_header>
<residuals> ... (différences de pixels) </residuals>
Total vecteurs sur 1 min 30fps : 8100 × 30 × 60 = 14 580 000 vecteurs
→ 2 composantes chacun → 29 160 000 valeurs encodables !Modification LSB des vecteurs
L'approche la plus simple consiste à modifier le bit de poids faible de chaque composante de motion vector. Une variation de ±1 (sur une plage de ±512) représente un déplacement de 0.25 pixel — imperceptible visuellement mais encodable.
Cette modification nécessite d'accéder au bitstream H.264 au niveau de l'encodeur (pas possible après coup sans décodage complet). Typiquement réalisé via un encodeur modifié (FFmpeg patché, x264 modifié).
MOTION VECTOR LSB EMBEDDING :
Pour chaque macroblock de chaque P/B-frame :
mv = encoder.compute_optimal_mv(macroblock, reference)
bit = next_secret_bit()
// Forcer le LSB de mv_x selon le bit à encoder
if mv_x % 2 != bit:
mv_x += 1 // ajuster d'un quart de pixel
store(mv_x, mv_y, macroblock_residuals)
DÉCODAGE :
Pour chaque macroblock P/B-frame :
mv_x = decode_motion_vector_x()
bit = mv_x & 1 // lire le LSB
message += bit
Capacité brute : 1 bit par composante par macroblock
Pour 1080p 30fps : 8100 macroblocks × 2 composantes × 30fps = 486 000 bits/seconde ≈ 60 Ko/sApproches avancées : sélection des vecteurs
Modifier tous les motion vectors laisse une signature détectable. Les approches avancées sélectionnent uniquement les macroblocks où la modification est la moins visible et la moins statistiquement anormale.
Macroblocks de texture complexe
DISCRETSélectionner les macroblocks avec une texture riche où une variation de ±1 dans le vecteur n'affecte pas la reconstruction perçue.
Vecteurs de grande amplitude
ROBUSTEUn vecteur (120, 87) modifié en (121, 87) est moins suspect qu'un vecteur (0, 1) modifié en (1, 1). Préférer les grands mouvements.
Sélection par clé secrète
SÉCURISÉN'utiliser qu'un sous-ensemble pseudo-aléatoire des macroblocks (sélectionné par clé). Rend la détection plus difficile sans la clé.
Odd-Even embedding
CLASSIQUEEncoder bit=0 → mv_x pair, bit=1 → mv_x impair. Ajuster mv_x de ±1 selon besoin. Identique au LSB mais formulé différemment.
Capacité et formats
| Résolution & fps | Macroblocks/frame | Capacité brute/s |
|---|---|---|
| 720p 30fps | 3 600 | ~27 Ko/s |
| 1080p 30fps | 8 100 | ~60 Ko/s |
| 4K 30fps | 32 400 | ~243 Ko/s |
| 4K 60fps | 32 400 | ~486 Ko/s |
Détection : anomalies de mouvement
Les motion vectors stéganographiés présentent des anomalies statistiques dans leur distribution. Un encodeur optimal choisit le motion vector qui minimise l'erreur de reconstruction. Modifier ce vecteur optimal crée une sous-optimalité détectable.
Résistance au transcodage
Si le débit est suffisamment conservé lors du transcodage, les motion vectors modifiés peuvent être préservés.
Distribution anormale
Les vecteurs modifiés ne correspondent pas à l'optimum théorique de l'estimation de mouvement. Détectable par analyse.
Parité artificielle
La parité des composantes de vecteur (LSB = 0 ou 1) présente une distribution uniforme artificielle au lieu d'une distribution naturelle.
Fragile au décodage/ré-encodage
Un transcodage complet avec ré-estimation du mouvement écrasera tous les motion vectors modifiés.
Questions fréquentes
C'est quoi un vecteur de mouvement en termes simples ?
Quand vous regardez une vidéo, une grande partie des frames est identique à la précédente (le fond ne bouge pas). Au lieu de stocker chaque frame complète, le codec H.264 cherche où les objets se sont déplacés et stocke juste le déplacement. Ce déplacement s'appelle vecteur de mouvement — par exemple (3, -2) signifie 3 pixels à droite, 2 vers le haut.
Pourquoi modifier ces vecteurs encode-t-il des données ?
Les vecteurs de mouvement sont nombreux et légèrement variables (plusieurs vecteurs valides existent pour un même bloc). En choisissant stratégiquement parmi les vecteurs valides selon un code secret, on encode des bits sans changer l'image visible. C'est une information 'méta' cachée dans la structure de la vidéo.
Est-ce utilisé par des malwares réels ?
Des techniques similaires ont été documentées dans des rapports de threat intelligence sur des groupes APT. Des C2 sophistiqués utilisent des vidéos sur des plateformes publiques comme YouTube pour transmettre des instructions à des implants, cachées dans la structure de la vidéo. Difficile à détecter car l'image visible semble parfaitement normale.
Comment se défendre contre ce type d'exfiltration ?
Inspection profonde des paquets (DPI) qui analyse le contenu des flux vidéo, analyse comportementale des postes (communications vers des services vidéo inhabituels), et listes blanches d'applications. La détection est difficile car le trafic ressemble à du visionnage vidéo totalement normal.
Peut-on l'utiliser pour du watermarking vidéo ?
Oui, et c'est un usage légitime important dans l'industrie du streaming. Les services de VOD (Netflix, Prime Video) utilisent des techniques de tatouage dans les métadonnées vidéo, dont les vecteurs de mouvement, pour identifier qui a enregistré et divulgué une copie premium d'un film.
Voir aussi
Comprenez d'abord le LSB sur image avant d'aborder les motion vectors.