Projet Subtitld
Le fichier propre à Subtitld : un paquet ZIP qui commence par un document USF des sous-titres, de leurs traductions, de leurs locuteurs et de leurs doublages, avec un manifeste de tout le reste, une image de l'endroit où vous vous êtes arrêté et, si vous le demandez, la vidéo et son son. Un seul fichier à déplacer, sauvegarder ou transmettre, et chacune de ses parties se lit avec des outils standard.
En bref
| Extension | .usfx |
|---|---|
| Type de média | application/x-usfx, une sorte d'application/zip. Sur les systèmes Apple, org.subtitld.usfx. |
| Spécification | Cette page. Le paquet est le ZIP de PKWARE (APPNOTE.TXT) ; le document est USF 1.0 avec les éléments de Subtitld. |
| Paquet | ZIP, ses membres compressés en Deflate (RFC 1951) et vérifiés par CRC-32 ; Zip64 pour les fichiers au-delà de 2 Gio |
| Premier membre | subtitles.usf : son nom est à l'octet 30 de chaque projet enregistré par Subtitld |
| Précision temporelle | Sous-titres : millisecondes. Doublages : les secondes exactes, avec autant de décimales qu'il le faut. |
| Encodage du texte | UTF-8, dans le XML et dans les noms des membres |
| Style | Celui d'USF : italique, gras, souligné, barré, couleur et neuf emplacements |
| Locuteurs | Un nom, une couleur, une image et une voix chacun |
| Langues | L'original et chaque traduction, un bloc chacun, par code ISO 639-2 et nom |
| Médias inclus | Les doublages et les images des locuteurs ; sur demande, la vidéo, son son, les voix et le fond séparés, et la forme d'onde de la timeline |
Anatomie d'un fichier
Un .usfx est un ZIP. N'importe quel outil d'archives l'ouvre, renommé en .zip si l'outil y tient.
Tears of Steel.usfx subtitles.usf manifest.xml thumbnail.png assets/speakers/Celia.png assets/dubs/77a03e27.wav assets/video/Tears_of_Steel.mkv assets/waveform.npy assets/audio/vocals.flac
- 1 · Document
Le projet lui-même, en USF : chaque sous-titre, traduction, locuteur et doublage. Toujours présent, toujours en premier.
- 2 · Manifeste
Ce qui a créé le fichier, où était la vidéo, comment le son était mixé, et un type de média pour chaque autre membre.
- 3 · Image
Ce que les gestionnaires de fichiers montrent du projet : l'image où vous vous êtes arrêté, son sous-titre et la timeline à cet endroit.
- 4 · Ressources
L'audio de chaque doublage et les visages des locuteurs ; la vidéo, son son et la forme d'onde seulement si vous le demandez.
Le document dit ce qui se passe ; les ressources sont ce qu'il joue. Un doublage dans subtitles.usf désigne son clip par son chemin dans le paquet, assets/dubs/77a03e27.wav, si bien que le paquet peut passer dans un autre dossier, sur un autre disque ou un autre ordinateur et rester entier.
Les membres
| Chemin | Contenu | Compression | Écrit |
|---|---|---|---|
subtitles.usf |
Le document : sous-titres, traductions, locuteurs, voix, doublages | Deflate | Toujours, en premier |
manifest.xml |
Le manifeste | Deflate | Toujours, en deuxième |
thumbnail.png |
Une carte PNG du projet, 512 × 384 | Stocké | Quand il y a une image à faire |
assets/speakers/<speaker>.png |
L'image d'un locuteur, 256 pixels de côté au plus | Deflate | Sauf si vous le désactivez |
assets/dubs/<uid>.<ext> |
L'audio d'une prise de doublage, nommé d'après l'identifiant de la prise | Deflate | Toujours, pour chaque prise avec de l'audio |
assets/dubs/<uid>__<n>__<file> |
Un morceau coupé ou étiré d'une prise, et la source intacte dont il a été étiré | Deflate | Quand une prise a été coupée ou étirée |
assets/video/<file> |
La vidéo | Deflate | Sur demande |
assets/waveform.npy |
Les crêtes de la forme d'onde de la timeline, un tableau NumPy | Deflate | Sur demande |
assets/audio/original.flac |
Le son de la vidéo | Deflate | Sur demande |
assets/audio/vocals.flac, background.flac |
Le son séparé en voix et en reste | Deflate | Sur demande |
Les noms dans assets/ sont faits de lettres, de chiffres, de -, _ et . ; tout le reste devient _, si bien que Tears of Steel.mkv est stocké sous Tears_of_Steel.mkv. Les lettres hors ASCII sont conservées, le nom écrit en UTF-8 et marqué comme tel (bit 11 de l'en-tête ZIP), comme le demande APPNOTE.
Pourquoi l'image est stockée et non compressée. Un PNG est déjà compressé ; Deflate ne ferait que coûter du temps. Stockés, ses octets sont dans le fichier exactement comme dans un PNG, et un générateur de vignettes les lit sans rien décompresser.
Les premiers octets
Chaque projet commence de la même façon : un en-tête de fichier local ZIP, puis le nom de son premier membre.
50 4B 03 04 14 00 00 00 08 00 4E 70 51 5D 64 CE 1E 0B 6F 3B 00 00 7F E2 00 00 0D 00 00 00 73 75 62 74 69 74 6C 65 73 2E 75 73 66
- 1 · Signature
PK\3\4, octets 0 à 3 : un membre ZIP commence ici. - 2 · En-tête
Version 2.0 nécessaire pour extraire ; aucun drapeau ; méthode 8, Deflate ; l'heure et la date, à la manière de MS-DOS (ici le 17 octobre 2026, 14:02:28) ; le CRC-32 ; les tailles compressée et décompressée (15 215 et 57 983 octets).
- 3 · Longueur du nom
13, et aucun champ supplémentaire.
- 4 · Nom
subtitles.usf, à partir de l'octet 30.
Le nom n'est jamais compressé, même quand le membre l'est. Cela en fait une signature : un ZIP dont le nom à l'octet 30 est subtitles.usf est un projet Subtitld. Le Tracker de Haiku distingue les projets des autres archives exactement par cette règle, 0.60 ("PK\003\004") [30] ("subtitles.usf" | "manifest.xml"), classée au-dessus de la règle du ZIP ordinaire. ODF et EPUB font de même avec un premier membre nommé mimetype.
Une vidéo peut dépasser la limite d'origine de ZIP, 4 Gio. À partir de 2 Gio, Subtitld écrit les champs supplémentaires et les enregistrements de fin de Zip64 (section 4.5 d'APPNOTE), comme il le fait au-delà de 65 535 membres ; Subtitld, son gestionnaire de vignettes Windows et tout unzip actuel les lisent.
Le manifeste
<?xml version="1.0" encoding="UTF-8"?>
<manifest version="1.0">
<format>USFX</format>
<generator>Subtitld</generator>
<source path="/home/ana/Videos/Tears of Steel.mkv"
basename="Tears of Steel.mkv"/>
<voicemix volume="0.5000"/>
<entry path="subtitles.usf" type="application/x-usf+xml"/>
<entry path="thumbnail.png" type="image/png"/>
<entry path="assets/speakers/Celia.png" type="image/png"/>
<entry path="assets/dubs/77a03e27.wav" type="audio/wav"/>
</manifest>
| Élément | Contenu |
|---|---|
<manifest version> |
La version du manifeste, 1.0 |
<format>, <generator> |
USFX, et ce qui a écrit le fichier : Subtitld |
<source path basename> |
Le chemin complet de la vidéo au moment de l'enregistrement du projet, et son seul nom de fichier |
<voicemix volume> |
La position du curseur Musique/Voix : 0 le fond seul, 0.5 le son tel quel, 1 les voix seules, les doublages s'effaçant avec le fond |
<entry path type> |
Un pour chaque membre sauf le manifeste lui-même, chacun avec son type de média |
Les types sont application/x-usf+xml, image/png, audio/wav, audio/flac, audio/mpeg, video/mp4, video/x-matroska, video/quicktime, video/webm, video/ogg, et application/octet-stream pour la forme d'onde et tout le reste.
Le chemin de la vidéo voyage avec le fichier. <source path> est l'endroit où se trouvait la vidéo sur l'ordinateur qui a enregistré le projet, dossiers et nom d'utilisateur compris. Gardez-le à l'esprit avant de partager un projet. Quand le chemin ne mène nulle part, Subtitld cherche la vidéo par son nom dans le dossier du projet.
Le document
subtitles.usf est un fichier Universal Subtitle Format, en UTF-8, tel que Subtitld l'écrit seul, avec ce dont un projet a besoin ajouté dans le style d'USF : des éléments et des attributs là où USF n'en a pas. Un lecteur USF qui ignore ce qu'il ne connaît pas lit ses sous-titres.
<USFSubtitles version="1.0"
xmlns:subtitldcc="https://subtitld.cc/ns/usf/1">
<metadata>
<title>Tears of Steel</title>
<author><name>Subtitld</name></author>
<language code="eng">English</language>
<subtitldcc:origin share-id="Xk3pQ9aZ2bT" version="3"/>
</metadata>
<styles>
<style name="Celia">
<fontstyle color="#e5484d"/>
<dubbing engine="edge-tts" voice="en-GB-SoniaNeural"
rate="0" pitch="0" fit_to_subtitle="true"/>
</style>
</styles>
<subtitles>
<language code="eng">English</language>
<subtitle start="00:00:23.000" stop="00:00:24.500">
<text speaker="Celia" style="Celia">You're a jerk, Thom.</text>
<dubbing uid="77a03e27" engine="edge-tts"
voice="en-GB-SoniaNeural" rate="0" pitch="0"
path="assets/dubs/77a03e27.wav"
start="23.0" end="24.5"/>
</subtitle>
</subtitles>
<subtitles>
<language code="por">Portuguese (Brazil)</language>
<subtitle start="00:00:23.000" stop="00:00:24.500">
<text speaker="Celia" style="Celia">Você é um idiota, Thom.</text>
</subtitle>
</subtitles>
</USFSubtitles>
Ce que Subtitld ajoute à USF
| Où | Élément ou attribut | Contenu |
|---|---|---|
<metadata> |
<subtitldcc:origin share-id version> |
Le sous-titre de subtitld.cc dont vient le projet, pour que les modifications puissent être publiées comme sa version suivante. Dans son propre espace de noms, https://subtitld.cc/ns/usf/1, écrit seulement quand il y en a un. |
<styles> |
<style name> |
Un pour chaque locuteur, à son nom. Pas de style Default, qui changerait le style de chaque sous-titre dans un lecteur. |
<style> |
<fontstyle color> |
La couleur du locuteur, #RRGGBB |
<style> |
<dubbing engine voice rate pitch fit_to_subtitle> |
La voix du locuteur : le moteur, la voix, le débit et la hauteur de −100 à 100, et si les doublages sont ajustés à la durée de leur sous-titre |
<text> |
speaker, style |
Qui le dit, et son style |
<text> |
alignment |
L'un des neuf emplacements d'USF, de TopLeft à BottomRight ; aucun pour le bas au centre |
<subtitle> |
<dubbing> |
Une prise du doublage du sous-titre, un élément chacune |
<dubbing> |
uid engine voice rate pitch |
L'identifiant de la prise, et la voix avec laquelle elle a été faite |
<dubbing> |
path, raw_path |
Son audio dans le paquet, et la source dont une prise étirée a été faite |
<dubbing> |
start, end |
Où elle joue sur la timeline, en secondes |
<dubbing> |
<subclip type path raw_path start end offset rate> |
Les morceaux d'une prise coupée ou étirée |
Dans un .usf ordinaire, les images des locuteurs et l'audio des doublages peuvent voyager dans le XML, en base64 dans <avatar> et <data>. Un .usfx ne le fait jamais : ce sont des membres à part entière, un quart plus petits qu'en base64, et lus sans analyser le XML.
Temps
Le start et le stop d'un sous-titre sont des temps USF, arrondis à la milliseconde la plus proche. Les temps d'un doublage sont de simples secondes écrites en entier, 18.01579117916244 : le décimal le plus court qui se relit comme le même nombre 64 bits, si bien qu'un clip placé en le faisant glisser revient exactement où il était.
Les anciennes versions de Subtitld écrivaient les temps une milliseconde trop tôt, et un début à zéro sous la forme 23:59:59.999. Subtitld lit cette valeur comme zéro, et laisse la milliseconde telle quelle.
Prises et sous-clips
Un sous-titre peut avoir plusieurs prises. Le premier <dubbing> est celui qui joue ; les autres sont des alternatives, muettes jusqu'à ce que vous en choisissiez une, qui passe alors en tête.
Une prise coupée ou étirée garde une liste de <subclip>, placés comme des clips dans un éditeur audio :
| Attribut | Signification |
|---|---|
start, end |
La partie du fichier source qui joue, en secondes depuis le début du fichier |
offset |
Où cette partie commence, en secondes depuis le start de la prise |
rate |
La vitesse à laquelle elle a été étirée : 20 correspond à 120 % |
path, raw_path |
L'audio qui joue, et l'audio intact dont il a été étiré |
Un sous-clip joue à partir du start de la prise plus son offset, pendant end moins start secondes. Les vides sont du silence ; les chevauchements sont mixés. Les sources ne sont jamais modifiées, si bien que chaque coupe et chaque étirement peuvent être annulés, et un étirement est toujours refait à partir de raw_path, jamais à partir de l'étirement d'un étirement.
Traductions
Chaque langue a son propre bloc <subtitles>, désigné par son code ISO 639-2 et, dans l'élément, par le nom de la langue, qui distingue le portugais du Brésil de celui du Portugal. Chaque bloc contient chaque sous-titre aux mêmes temps ; seul le premier contient des doublages. Subtitld associe une traduction à son sous-titre par l'heure de début, ou à celui qu'elle chevauche le plus, si bien que les blocs écrits par d'autres outils n'ont pas besoin de s'aligner.
Ouvrir un projet
Les gros projets s'ouvrent tout de suite : Subtitld lit d'abord ce dont l'éditeur a besoin, et le reste pendant que vous travaillez.
subtitles.usf, lu pour les sous-titres, les locuteurs et les voixmanifest.xml, pour la vidéo et le mixageassets/speakers/, les visages, décodés hors du fil principal- Une vidéo incluse, extraite une seule fois
- Les doublages d'abord, pour que vous puissiez les écouter
- La forme d'onde, ensuite
- Le son séparé, en dernier
Chaque doublage sur la timeline est hachuré jusqu'à l'arrivée de son audio, puis il joue.
Les membres sont extraits dans les dossiers propres à Subtitld, jamais à côté du projet : le document, les visages et les doublages dans un dossier de cache nommé d'après le MD5 du chemin du projet. Ce qui arrive pendant que vous travaillez est écrit par blocs de 1 Mio dans un fichier temporaire, renommé à sa place une fois complet, si bien qu'un plantage en cours de route ne laisse rien d'à moitié écrit. La fois suivante où le même projet s'ouvre, un fichier déjà présent n'est réutilisé que s'il a exactement la taille du membre ; sinon il est extrait de nouveau.
La vidéo est cherchée dans cet ordre :
- une vidéo dans le paquet, dans
assets/video/; - le chemin dans
<source path>, s'il existe encore ; - un fichier nommé comme dans
<source basename>, dans le dossier du projet ; - sinon, Subtitld la demande.
Un fichier qui n'est pas un ZIP, qui est tronqué ou qui échoue à un contrôle CRC n'ouvre rien : Subtitld le signale et le retire de la liste des fichiers récents. Les projets plus anciens s'ouvrent aussi : un projet sans manifeste, ou dont l'USF porte un autre nom à la racine du ZIP.
Enregistrer un projet
Enregistrer ne met jamais en danger le projet que vous avez.
- Un instantané. Le projet est copié tel qu'il est quand vous enregistrez, pour que vous puissiez continuer à modifier pendant qu'il est écrit. Enregistrements, enregistrements automatiques et sauvegardes se relaient : un seul écrit à la fois.
- Un nouveau fichier. Le paquet est écrit dans
<project>.usfx.tmpà côté du projet. - Rien ne manque. Un doublage dont l'audio n'est pas encore dans le cache, encore en cours d'arrivée ou effacé, est copié depuis le fichier sur le point d'être remplacé. Un projet enregistré sans vidéo garde l'image qu'il avait.
- Vérifié. Le nouveau fichier est rouvert et le CRC-32 de chaque membre vérifié.
- Échangé. Alors seulement il remplace le projet, en un seul renommage (
os.replace) : le nom du projet ne contient jamais un demi-projet.
Si une étape échoue, le fichier temporaire est supprimé, le projet sur le disque est celui que vous aviez, et vos modifications sont toujours ouvertes dans Subtitld. Tant que les doublages d'un projet sont encore en cours d'arrivée, Enregistrer les attend.
Ce qui va dedans
Réglages généraux, puis USFX, choisit ce qu'un projet emporte en plus, pour chaque projet que vous enregistrez :
- Portraits des locuteursLes visages des locuteurs. Activé.
- Cache de la forme d'onde de la timelineLa forme d'onde, pour qu'un projet s'ouvre sur un autre ordinateur sans la recalculer. Désactivé.
- Piste audio originaleLe son de la vidéo, en FLAC. Désactivé.
- Audio traité (voix + fond)Le son séparé en voix et en reste, en FLAC, pour que la séparation n'ait pas à tourner de nouveau. Désactivé.
- Fichier vidéo originalLa vidéo elle-même : un seul fichier avec tout, aussi gros que la vidéo et plus. Désactivé.
Chacun entre quand Subtitld en a un à y mettre : le son séparé, par exemple, seulement une fois la séparation faite. Les sous-titres, les traductions, les locuteurs, les voix et chaque doublage sont toujours dedans. Deflate retire environ un sixième du WAV d'un doublage ; une vidéo et du FLAC rétrécissent à peine.
Enregistrement automatique et sauvegardes
- Enregistrer automatiquement le fichier du projetÉcrit votre
.usfxlui-même, comme le fait Enregistrer, de la même manière sûre. Pour un projet enregistré en USFX. - Sauvegardes automatiquesUn
.usfxcomplet dans le dossier de sauvegarde de Subtitld, à l'écart de votre propre fichier, nommé<project>_<YYYYMMDDHHMMSS>.usfx, quand il y a des modifications à garder. Au-delà de Conserver au maximum, 20 sauf choix contraire, les plus anciennes sont supprimées.
Dans les gestionnaires de fichiers
La vignette est une carte à l'allure de Subtitld : l'image de la vidéo où le projet a été laissé, le sous-titre dessus, et en dessous les douze secondes de timeline autour de la tête de lecture, la forme d'onde et les sous-titres aux couleurs de leurs locuteurs. En 4:3 à 512 × 384, elle remplit mieux la case carrée d'un gestionnaire de fichiers qu'une image large. Sans vidéo, l'emblème de Subtitld remplace l'image.
| Système | Le type | Ce qu'il apporte |
|---|---|---|
| Linux | application/x-usfx dans shared-mime-info, une sorte d'application/zip, reconnu par *.usfx |
Une icône à lui ; avec le paquet AUR, des vignettes de subtitld-thumbnailer, un générateur de vignettes freedesktop.org |
| Windows | Un type de fichier dans l'installateur et le paquet MSIX | Une icône ; un fournisseur de vignettes du shell (UsfxThumbnail.dll, IThumbnailProvider) qui lit lui-même le répertoire central du ZIP, Zip64 compris, et décode le PNG avec WIC à la taille que demande l'Explorateur |
| macOS | Le type org.subtitld.usfx, conforme à public.zip-archive |
Une icône à lui |
| Haiku | application/x-usfx, avec la règle de détection ci-dessus |
Une icône, et un Tracker qui distingue un projet d'un ZIP |
D'un double-clic, un projet s'ouvre dans Subtitld sur les quatre. Les deux générateurs de vignettes ne lisent que thumbnail.png, refusent une image de plus de 8 Mio, et n'acceptent rien qui ne commence par la signature du PNG, 89 50 4E 47 0D 0A 1A 0A. Celui de Windows ne la prend que stockée, comme Subtitld l'écrit. Celui de Linux n'utilise que la bibliothèque standard de Python, car les gestionnaires de fichiers lancent les générateurs de vignettes isolés et nombreux à la fois.
Lire un .usfx soi-même
Rien dans un projet n'appartient à Subtitld seul. Pour regarder dedans :
unzip -l "Tears of Steel.usfx"
unzip -p "Tears of Steel.usfx" manifest.xml
Pour lire ses sous-titres, dans chaque langue, avec la bibliothèque standard de Python :
import zipfile
import xml.etree.ElementTree as ET
def text_of(element):
"""A <text>'s words, <br/> as a line break."""
parts = [element.text or '']
for child in element:
parts.append('\n' if child.tag == 'br' else text_of(child))
parts.append(child.tail or '')
return ''.join(parts)
with zipfile.ZipFile('Tears of Steel.usfx') as usfx:
usf = ET.fromstring(usfx.read('subtitles.usf'))
for block in usf.iter('subtitles'):
language = block.find('language')
if language is not None:
print('#', language.get('code'), language.text)
for subtitle in block.iter('subtitle'):
text = subtitle.find('text')
print(subtitle.get('start'), subtitle.get('stop'),
text.get('speaker'), text_of(text))
Pour un projet venu de quelqu'un d'autre, analysez avec defusedxml à la place de xml.etree, comme pour tout XML que vous n'avez pas écrit.
En faire un
Le plus petit projet que Subtitld ouvre est un ZIP contenant un subtitles.usf. Sans manifeste, Subtitld demande la vidéo. Pour en faire un que les gestionnaires de fichiers reconnaissent aussi, suivez ce qu'écrit Subtitld :
subtitles.usfen premier, puismanifest.xml;- chaque membre compressé en Deflate, sauf
thumbnail.png, stocké ; - les doublages sous
assets/dubs/, désignés dans le document par leur chemin dans le paquet ; - de l'UTF-8 partout.
Subtitld garde ce qu'il connaît. Un enregistrement écrit les membres décrits sur cette page, et un document fait de ce que Subtitld a compris de l'ancien. Un fichier qu'un autre outil ajoute au paquet, ou un élément à lui dans l'USF, disparaît dès que Subtitld enregistre le projet. Gardez vos propres données à côté.
Comparaison
USFX est construit comme les paquets de documents des suites bureautiques et des livres numériques : un ZIP, un document principal en XML, un inventaire, les médias à côté.
ODF (.odt) |
EPUB | Office Open XML (.docx) |
USFX | |
|---|---|---|---|---|
| Norme | OASIS ODF 1.3, partie 2 | W3C EPUB 3.3, son OCF | ECMA-376 partie 2, OPC | Cette page |
| Comment un outil le reconnaît | Un premier membre mimetype, stocké |
Un premier membre mimetype, stocké : application/epub+zip |
[Content_Types].xml |
Le nom de son premier membre, subtitles.usf, à l'octet 30 |
| Inventaire | META-INF/manifest.xml, un type pour chaque fichier |
META-INF/container.xml, puis le document de paquet |
[Content_Types].xml et _rels/ |
manifest.xml, un type pour chaque membre |
| Document principal | content.xml |
Le document de paquet et son spine | word/document.xml |
subtitles.usf |
| Médias | Pictures/ |
N'importe où dans le paquet | word/media/ |
assets/ |
| Aperçu | Thumbnails/thumbnail.png |
Une image de couverture | Une partie vignette facultative | thumbnail.png, stocké |
Le document principal est un format ouvert à part entière : sortez le subtitles.usf d'un .usfx et c'est un fichier USF, un format à la spécification publique depuis 2002.
Anecdotes
L'octet où commence le nom du premier membre de chaque projet, et la façon dont Haiku distingue un projet Subtitld de n'importe quel autre ZIP.
La taille de l'image d'un projet : 4:3, parce que les gestionnaires de fichiers montrent les fichiers dans des carrés.
La version qui a donné au .usfx une icône à lui sous Linux, Windows, macOS et Haiku, et son image dans l'Explorateur Windows et les gestionnaires de fichiers Linux.
Formats associés
-
.usfUniversal Subtitle Format
-
.jsonSous-titres et transcriptions JSON
-
.ttmlTimed Text Markup Language
Ouvrez une vidéo dans Subtitld, faites ses sous-titres et enregistrez : c'est un .usfx.