Transcription, traduction, sous-titrage avec un outil d'IA

Motivations

Le projet INCLUDE a soulevé un certain nombre de questions sur l'accessibilité numérique des documents produits par les enseignants. L'utilisation des e-pub3.2+accessibility1.0 a été proposé comme l'une des solutions possibles, toutefois le respect de ces normes qui introduit un balisage avec un vocabulaire issu de schema.org ne fournit ni transcription des audio, ni sous-titrage. Le but de ce travail est de décrire une méthode utilisée pour enrichir les vidéos incluses dans les livres numériques au format e-pub et plus généralement toute vidéo dont on souhaiterait améliorer l'accessibilité pour les malentendants.


Avertissement

Lorsque j'ai réalisé ce travail je n'avais absolument pas perçu que je mettais en oeuvre un outil d'IA. J'avais simplement vérifié que le code était ouvert (licence MIT et communauté ouverte sur GitHub) sans aller plus loin dans l'investigation. L'outil whisper est partagé avec la communauté par la société OpenAI qui porte aussi chatGPT à propos duquel les discussions occupent le devant de la scène en ce moment. Whisper n'est pas un dérivé de chatGPT mais partage avec lui le même modèle.

GPT signifie "Generative Pre-trained Transformer" et fait partie de la famille des LLM "Large Language Model"; le pré-entrainement consiste à exposer l'algorithme à un gigantesque corpus de ressources à partir duquel par essais/évaluation successifs est affinée une échelle de probabilités d'enchainement de mots (ou de "tokens" selon le langage openAI qui correspondent plus ou mois à une partie de mot liée à une de ses racines).

On conçoit aisément que si en plus d'un outils de génération de texte on dispose d'un moteur capable de transcrire même rudimentairement les phonèmes en représentation textuelle, cela fournit à l'algorithme de génération des indications décisives pour choisir à tout moment de la lecture, avec une probabilité extrêmement forte, le mot suivant de la chaîne constituant la phrase enregistrée. Cela se traduit par la performance élevée de cet outil de transcription qui m'avait séduit.

je ne souhaite pas ici entrer dans le débat sur IA et enseignement, il me semble que le fait que chacun puisse contrôler les résultats de l'exécution avant de les diffuser, intervenir facilement sur quelques paramètres simples du modèle, contribuer à l'évolution ou modifier librement le code source du logiciel suffit à garantir durablement un usage sain et neutre. Un autre argument est fourni par les angagements éthiques d'openAI.

Remerciements

Éric le Jan et Charles-Henri Eyraud, Carole Larose, Benkouar Benyoucef.


Sommaire

Ajouter des sous-titres à une vidéo

  1. Installation des logiciels
    1. Linux
    2. Windows
  2. Extraction de la piste audio d'une vidéo
  3. Transcription du fichier audio
  4. Correction du fichier texte issu de l'audio
  5. Ajout du canal de sous-titres à la vidéo
    1. Sous-titres en "overlay"
    2. Sous-titres en "incrustation"
  6. Conclusion

Téléchargements

  1. jubler/
  2. whisper
  3. ffmpeg (Marillat version)

Ajouter des sous-titres à une vidéo

Les sous-titres dérivent forcément d'un fichier audio la procédure de sous-titrage requiert une étape préliminaire de traitement de la vidéo afin d'extraire le son sous forme d'un fichier audio. On utilise trois logiciels pour réaliser complètement la procédure :

  • whisper
  • jubler
  • ffmpeg

Déroulé

La procédure de transcription se déroule en trois étapes utilisant chacune l'un des logiciels installés avec les commandes ci-dessus :

  1. on extrait l'audio de la vidéo -> ffmpeg
  2. on réalise la transcription de l'audio (avec correction si besoin) -> whisper (+ jubler )
  3. on intègre les sous-titres à la vidéo -> ffmpeg

1. Installation des logiciels

1.1 Linux

L'installation détaillée ci-dessous concerne l'OS linux, pour les autres OS se reporter aux instructions détaillées depuis les pages de garde des 3 logiciels

Pour whisper il est nécessaire de créer un environnement virtuel python qui est la façon préconnisée pour gérer un logiciel avec des dépendances sans perturber le fonctionnement du système (nous utilisons ici pipenv mais les autres solutions de Virt.Envs python sont tout aussi valides). De plus au moment de l'installation (04-12-23) openai-whisper imposait l'usage de python < 3.11 à cause de la version de numba qui n'est pas encore adaptée à python3.11, cette limitation étant susceptible d'évoluer avec les mises à disposition de nouvelles versions de python3. Deux solutions sont possibles, soit on utilise python3.9 ou python3.10 soit on installe indépendamment numba avant d'installer whisper avec la commande pipenv install "numba==0.57.0rc1" dans l'environnement virtuel.

mkdir -p Whisper/VenvWhisper
cd Whisper/VenvWhisper
pipenv --python 3.10 install openai-whisper pycuda torchaudio torchvision openai

Nous proposons d'installer la version deb-multimedia qui propose par défaut l'utilisation de fragments non libres mais qui en contrepartie fournit une grande souplesse d'utilisation en éliminant quelques incompatibilités. Pour les distributions Linux Debian et dérivées, ajouter dans /etc/apt/sources.list.d un fichier ffmpegMarillat.list contenant deb https://www.deb-multimedia.org bookworm main non-free puis effectuer les commandes suivantes.

sudo apt update -oAcquire::AllowInsecureRepositories=true
sudo apt install deb-multimedia-keyring
sudo apt install ffmpeg 

Jubler propose un appimage directement exécutable, j'ai pris l'habitude de les copier dans mon /usr/local/bin.

wget https://github.com/teras/Jubler/releases/download/v7.0.3/Jubler-7.0.3.x86_64.appimage
chmod a+x Jubler-7.0.3.x86_64.appimage
sudo cp Jubler-7.0.3.x86_64.appimage /usr/local/bin/jubler

1.2 Windows

La méthode la plus simple (la seule que j'ai pu mener à bien) reste d'installer un linux à l'intérieur de windows puis de suivre ensuite la procédure proposée pour linux hormis pour jublerqui peut être directement installé depuis le site. Windows limite les ressources et les affichages de linux mais le logiciel est fonctionnel.

2. Extraction de la piste audio d'une vidéo

Il est utile de déterminer la structure de la vidéo utilisée afin de reconnaître les différentes pistes présentes. La commande ffprobe nomVidéo fournie par ffmpeg fait parfaitement ce travail :

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'video1.mp4':
  Metadata:
    major_brand     : mp42
    minor_version   : 1
    compatible_brands: mp41mp42isom
    creation_time   : 2023-02-27T22:26:28.000000Z
  Duration: 00:09:07.10, start: 0.000000, bitrate: 482 kb/s
  Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive),  [SAR 1:1 DAR 706:415], 346 kb/s, 60 fps, 60 tbr, 15360 tbn (default)
    Metadata:
      creation_time   : 2023-02-27T22:26:28.000000Z
      handler_name    : Core Media Video
      vendor_id       : [0][0][0][0]
      encoder         : Lavc59.37.100 libx264
  Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 127 kb/s (default)
    Metadata:
      creation_time   : 2023-02-27T22:26:28.000000Z
      handler_name    : Core Media Audio
      vendor_id       : [0][0][0][0]

Sur les données ci-dessus on peut lire que la vidéo utilisée dure 00:09:07.10 soit 9 minutes 7 secondes, elle fait 1412x830 pixels Elle contient 2 flux :

  • Un flux vidéo #0:0[0x1](und): Video: h264 le codec est H264
    • rapport de forme des pixels stockés SAR 1:1
    • rapport d'aspect de l'affichage de la vidéo attendu DAR 706:415 ce rapport bizarre est issu de la taille de la fenêtre de l'ordinateur qui a été enregistrée.
  • Un flux audio #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D) le codec est du acc, la désignation mp4a (parfois m4a) signifie qu'il s'agit d'un audio intégrée dans un conteneur mp4

Pour extraire l'audio la commande suivante permet de récupérer le fichier audio pour les traitements ultérieurs.

ffmpeg -i video1.mp4 -vn -acodec copy  video1.aac

Les paramètres indiquent -vn pas de vidéo et -acodec copy copie du codec audio. On obtient un fichier audio au format aac qui est immediatement accessible par whisper.

3. Transcription du fichier audio

Pour la transcription on utilise le logiciel ai-whisper qui dispose d'un grand nombre de paramètres permettant de moduler le modèle utilisé et les fonctions choisies pour les opérations. On utilise l'environnement virtuel créé dans le premier paragraphe. Si vous êtes équipés d'une carte vidéo puissante avec les logiciels d'exploitation de sa puissance de calcul installés, whisper tentera de l'utiliser afin de minimiser le tamps de calcul, attention à la taille mémoire du modèle utilisé ! Si vous n'avez pas trop de mémoire sur la carte vidéo pensez à utiliser les petits modèles sinon le manque de mémoire indut des fautes aléatoires dont les messages sont peu explicites et ne renvoient pas forcément et explicitement l'avertissement d'un manque de mémoire. Il est toujours possible de contraindre l'exécution sur le CPU central avec l'option --device (Pour les cartes vidéo, j'ai testé seulement l'exécution sur une nvidia avec CUDA qui a parfaitement fonctionné, j'essaierai une AMD si j'en trouve une que je parvienne à configurer). La commande ci-dessous liste les principales options de whisper.

cd Whisper/VenvWhisper/
pipenv run whisper --help
usage: whisper [-h] [--model {tiny.en,tiny,base.en,base,small.en,small,medium.en,medium,large-v1,large-v2,large}] [--model_dir MODEL_DIR] [--device DEVICE]
               [--output_dir OUTPUT_DIR] [--output_format {txt,vtt,srt,tsv,json,all}] [--verbose VERBOSE] [--task {transcribe,translate}]
               [--language {af,am,ar,as,az,ba,be,bg,bn,bo,br,bs,ca,cs,cy,da,de,el,en,es,et,eu,fa,fi,fo,fr,gl,gu,ha,haw,he,hi,hr,ht,hu,hy,id,is,it,ja,jw,ka,kk,km,kn,ko,la,lb,ln,lo,lt,lv,mg,mi,mk,ml,mn,mr,ms,mt,my,ne,nl,nn,no,oc,pa,pl,ps,pt,ro,ru,sa,sd,si,sk,sl,sn,so,sq,sr,su,sv,sw,ta,te,tg,th,tk,tl,tr,tt,uk,ur,uz,vi,yi,yo,zh,Afrikaans,Albanian,Amharic,Arabic,Armenian,Assamese,Azerbaijani,Bashkir,Basque,Belarusian,Bengali,Bosnian,Breton,Bulgarian,Burmese,Castilian,Catalan,Chinese,Croatian,Czech,Danish,Dutch,English,Estonian,Faroese,Finnish,Flemish,French,Galician,Georgian,German,Greek,Gujarati,Haitian,Haitian Creole,Hausa,Hawaiian,Hebrew,Hindi,Hungarian,Icelandic,Indonesian,Italian,Japanese,Javanese,Kannada,Kazakh,Khmer,Korean,Lao,Latin,Latvian,Letzeburgesch,Lingala,Lithuanian,Luxembourgish,Macedonian,Malagasy,Malay,Malayalam,Maltese,Maori,Marathi,Moldavian,Moldovan,Mongolian,Myanmar,Nepali,Norwegian,Nynorsk,Occitan,Panjabi,Pashto,Persian,Polish,Portuguese,Punjabi,Pushto,Romanian,Russian,Sanskrit,Serbian,Shona,Sindhi,Sinhala,Sinhalese,Slovak,Slovenian,Somali,Spanish,Sundanese,Swahili,Swedish,Tagalog,Tajik,Tamil,Tatar,Telugu,Thai,Tibetan,Turkish,Turkmen,Ukrainian,Urdu,Uzbek,Valencian,Vietnamese,Welsh,Yiddish,Yoruba}]
               [--temperature TEMPERATURE] [--best_of BEST_OF] [--beam_size BEAM_SIZE] [--patience PATIENCE] [--length_penalty LENGTH_PENALTY]
               [--suppress_tokens SUPPRESS_TOKENS] [--initial_prompt INITIAL_PROMPT] [--condition_on_previous_text CONDITION_ON_PREVIOUS_TEXT] [--fp16 FP16]
               [--temperature_increment_on_fallback TEMPERATURE_INCREMENT_ON_FALLBACK] [--compression_ratio_threshold COMPRESSION_RATIO_THRESHOLD]
               [--logprob_threshold LOGPROB_THRESHOLD] [--no_speech_threshold NO_SPEECH_THRESHOLD] [--word_timestamps WORD_TIMESTAMPS]
               [--prepend_punctuations PREPEND_PUNCTUATIONS] [--append_punctuations APPEND_PUNCTUATIONS] [--threads THREADS]
               audio [audio ...]

positional arguments:
  audio                 audio file(s) to transcribe

options:
  -h, --help            show this help message and exit
  --model {tiny.en,tiny,base.en,base,small.en,small,medium.en,medium,large-v1,large-v2,large}
                        name of the Whisper model to use (default: small)
  --model_dir MODEL_DIR
                        the path to save model files; uses ~/.cache/whisper by default (default: None)
  --device DEVICE       device to use for PyTorch inference (default: cpu)
  --output_dir OUTPUT_DIR, -o OUTPUT_DIR
                        directory to save the outputs (default: .)
  --output_format {txt,vtt,srt,tsv,json,all}, -f {txt,vtt,srt,tsv,json,all}
                        format of the output file; if not specified, all available formats will be produced (default: all)
  --verbose VERBOSE     whether to print out the progress and debug messages (default: True)
  --task {transcribe,translate}
                        whether to perform X->X speech recognition ('transcribe') or X->English translation ('translate') (default: transcribe)
  --language {af,am,ar,as,az,ba,be,bg,bn,bo,br,bs,ca,cs,cy,da,de,el,en,es,et,eu,fa,fi,fo,fr,gl,gu,ha,haw,he,hi,hr,ht,hu,hy,id,is,it,ja,jw,ka,kk,km,kn,ko,la,lb,ln,lo,lt,lv,mg,mi,mk,ml,mn,mr,ms,mt,my,ne,nl,nn,no,oc,pa,pl,ps,pt,ro,ru,sa,sd,si,sk,sl,sn,so,sq,sr,su,sv,sw,ta,te,tg,th,tk,tl,tr,tt,uk,ur,uz,vi,yi,yo,zh,Afrikaans,Albanian,Amharic,Arabic,Armenian,Assamese,Azerbaijani,Bashkir,Basque,Belarusian,Bengali,Bosnian,Breton,Bulgarian,Burmese,Castilian,Catalan,Chinese,Croatian,Czech,Danish,Dutch,English,Estonian,Faroese,Finnish,Flemish,French,Galician,Georgian,German,Greek,Gujarati,Haitian,Haitian Creole,Hausa,Hawaiian,Hebrew,Hindi,Hungarian,Icelandic,Indonesian,Italian,Japanese,Javanese,Kannada,Kazakh,Khmer,Korean,Lao,Latin,Latvian,Letzeburgesch,Lingala,Lithuanian,Luxembourgish,Macedonian,Malagasy,Malay,Malayalam,Maltese,Maori,Marathi,Moldavian,Moldovan,Mongolian,Myanmar,Nepali,Norwegian,Nynorsk,Occitan,Panjabi,Pashto,Persian,Polish,Portuguese,Punjabi,Pushto,Romanian,Russian,Sanskrit,Serbian,Shona,Sindhi,Sinhala,Sinhalese,Slovak,Slovenian,Somali,Spanish,Sundanese,Swahili,Swedish,Tagalog,Tajik,Tamil,Tatar,Telugu,Thai,Tibetan,Turkish,Turkmen,Ukrainian,Urdu,Uzbek,Valencian,Vietnamese,Welsh,Yiddish,Yoruba}
                        language spoken in the audio, specify None to perform language detection (default: None)
  --temperature TEMPERATURE
                        temperature to use for sampling (default: 0)
  --best_of BEST_OF     number of candidates when sampling with non-zero temperature (default: 5)
  --beam_size BEAM_SIZE
                        number of beams in beam search, only applicable when temperature is zero (default: 5)
  --patience PATIENCE   optional patience value to use in beam decoding, as in https://arxiv.org/abs/2204.05424, the default (1.0) is equivalent to conventional beam search
                        (default: None)
  --length_penalty LENGTH_PENALTY
                        optional token length penalty coefficient (alpha) as in https://arxiv.org/abs/1609.08144, uses simple length normalization by default (default: None)
  --suppress_tokens SUPPRESS_TOKENS
                        comma-separated list of token ids to suppress during sampling; '-1' will suppress most special characters except common punctuations (default: -1)
  --initial_prompt INITIAL_PROMPT
                        optional text to provide as a prompt for the first window. (default: None)
  --condition_on_previous_text CONDITION_ON_PREVIOUS_TEXT
                        if True, provide the previous output of the model as a prompt for the next window; disabling may make the text inconsistent across windows, but the
                        model becomes less prone to getting stuck in a failure loop (default: True)
  --fp16 FP16           whether to perform inference in fp16; True by default (default: True)
  --temperature_increment_on_fallback TEMPERATURE_INCREMENT_ON_FALLBACK
                        temperature to increase when falling back when the decoding fails to meet either of the thresholds below (default: 0.2)
  --compression_ratio_threshold COMPRESSION_RATIO_THRESHOLD
                        if the gzip compression ratio is higher than this value, treat the decoding as failed (default: 2.4)
  --logprob_threshold LOGPROB_THRESHOLD
                        if the average log probability is lower than this value, treat the decoding as failed (default: -1.0)
  --no_speech_threshold NO_SPEECH_THRESHOLD
                        if the probability of the <|nospeech|> token is higher than this value AND the decoding has failed due to `logprob_threshold`, consider the segment
                        as silence (default: 0.6)
  --word_timestamps WORD_TIMESTAMPS
                        (experimental) extract word-level timestamps and refine the results based on them (default: False)
  --prepend_punctuations PREPEND_PUNCTUATIONS
                        if word_timestamps is True, merge these punctuation symbols with the next word (default: "'“¿([{-)
  --append_punctuations APPEND_PUNCTUATIONS
                        if word_timestamps is True, merge these punctuation symbols with the previous word (default: "'.。,,!!??::”)]})
  --threads THREADS     number of threads used by torch for CPU inference; supercedes MKL_NUM_THREADS/OMP_NUM_THREADS (default: 0)

La commande utilisée avec une configuration minimaliste permet de produire un fichier au format srt (le modèle medium ne passe pas sur ma carte NVIDIA GeForce GTX 1660 SUPER avec un bureau ouvert mais Xorg,firefox et thunderbird mobilisent un peu plus de 800M, medium passe peut-être en mode console...). Tous les centres de calcul proposent des machines équipées de grosses cartes graphiques de calcul qui peuvent au besoin sous-traiter ce calcul.

whisper --model small --task transcribe --output_format srt --language fr video1.aac

Commande pour produire les sous-titres en anglais (penser à changer le nom du fichier srt qui sera écrasé sinon) :

whisper --model small --output_format srt --task translate --language fr video1.aac

4. Correction du fichier texte issu de l'audio

Le fichier produit par ai-whisper malgré le support d'un modèle d'IA peut ne pas être exempt d'anomalies, il est nécessaire de relire le fichier afin de corriger les éventuelles erreurs qui auraient échappé au dispositif automatisé (À titre d'exemple sur le fichier traité ici on a relevé une seule erreur). On utilise pour cela l'interface graphique du logiciel jubler. Ouvrir le fichier srt puis cliquer sur chaque ligne qui doit être corrigée et effectuer les corrections nécessaires puis sauvegarder le fichier.

5. Ajout du canal de sous-titres à la vidéo

La dernière opération consiste à ajouter le ou les canaux de sous-titres à la vidéo originelle. Deux méthodes sont possibles et éventuellement complémentaires :

  • ajouter les sous-titres dans des canaux indépendants ("overlay" ce qui requiert, pour les voir, un lecteur capable de détecter ces canaux et d'en afficher un ou un autre ou de les masquer à la demande)
  • incruster les sous-titres dans l'image sous la forme d'une surcouche (incrustation), il n'y a pas de canal supplémentaire créé et la vidéo affiche en permanence les sous-titres.

5.1. Sous-titres en "overlay"

Cette méthode est la plus simple et la moins consommatrice de temps car les images de la vidéo ne sont pas modifiées et les sous-titres ajoutés sous la forme d'un canal supplémentaire qui doit être géré par le lecteur. L'intérêt majeur est qu'un utilisateur ne souhaitant pas lire les sous-titres pourra afficher l'image intacte et celui qui souhaite les lire les afficher en transparence. On utilise la commande ffmpeg suivante à partir de la vidéo video1.mp4 avec les sous-titres video1.srt produits précédemment :

ffmpeg -i  video1.mp4 -i video1.srt -c copy -c:s mov_text video1+sstit.mp4

On a alors une vidéo contenant 3 flux :

ffprobe video1+sstit.mp4

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'video1+sstit.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf59.27.100
  Duration: 00:09:07.12, start: 0.000000, bitrate: 487 kb/s
  Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1412x830 [SAR 1:1 DAR 706:415], 346 kb/s, 60 fps, 60 tbr, 15360 tbn (default)
    Metadata:
      handler_name    : Core Media Video
      vendor_id       : [0][0][0][0]
      encoder         : Lavc59.37.100 libx264
  Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 127 kb/s (default)
    Metadata:
      handler_name    : Core Media Audio
      vendor_id       : [0][0][0][0]
  Stream #0:2[0x3](und): Subtitle: mov_text (tx3g / 0x67337874), 0 kb/s (default)
    Metadata:
      handler_name    : SubtitleHandler
../...

Il est aussi possible de rajouter une seconde piste de sous-titres, par exemple ici en anglais avec le fichier video1-en.srt :

ffmpeg -i video1+sstit.mp4 -i video1-en.srt -map 0 -map 1 -vcodec copy -acodec copy -c:s:0 copy -c:s:1 copy -c:s:1 mov_text  -metadata:s:s:1 language=English video1+2sstit.mp4

Le fichier vidéo présentee alors 2 flux de sous-titres :

ffprobe video1+2sstit.mp4

.../...

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'video1+2sstit.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf59.27.100
  Duration: 00:09:07.12, start: 0.000000, bitrate: 487 kb/s
  Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1412x830 [SAR 1:1 DAR 706:415], 346 kb/s, 60 fps, 60 tbr, 15360 tbn (default)
    Metadata:
      handler_name    : Core Media Video
      vendor_id       : [0][0][0][0]
      encoder         : Lavc59.37.100 libx264
  Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 127 kb/s (default)
    Metadata:
      handler_name    : Core Media Audio
      vendor_id       : [0][0][0][0]
  Stream #0:2[0x3](und): Subtitle: mov_text (tx3g / 0x67337874), 0 kb/s (default)
    Metadata:
      handler_name    : SubtitleHandler
  Stream #0:3[0x4]: Subtitle: mov_text (tx3g / 0x67337874), 0 kb/s
    Metadata:
      handler_name    : SubtitleHandler

Il est aussi possible de rajouter plusieurs sous-titres directement en une seule passe ici pour le film curationIFE Le lien conduit à la vidéo avec sous-titres (à visualiser sur un player capable de les détecter VLC par exemple) :

ffmpeg -i curationIFE.mp4 -i curationIFE-fr-cor.srt -i curationIFE-en-cor.srt  -map 0:v -map 0:a  -map 1 -map 2 -c:v copy -c:a copy -c:s mov_text -metadata:s:s:0 language=fre -metadata:s:s:1 language=eng curationIFE+sstt.mp4

Dans un player capable de détecter les sous-titres (par exemple VLC) on a alors desux "pistes" proposées dans l'onglet sous-titres.

5.2. Sous-titres en "incrustation"

L'incrustation des sous-titres est une opération un peu plus complexe car les images de la vidéo qui contiennent des sous-titres sont recomposées en incrustant dans l'image le sous-titre ce qui impose de modifier tous les pixels correspondant à la surface des sous-titres. Une difficulté supplémentaire vient (au moins pour la méthode proposée) de ce qu'il faille utiliser le format .ass au lieu de .srt pour les sous-titres, une conversion de format est donc nécessaire en amont. La manipulation a été réalise avec l'enchaînement de commandes suivant :

ffmpeg -i video1.srt video1.ass # produit le fichier de sous-titres au format ass
ffmpeg -i video1.mp4 -filter_complex "subtitles=video1.ass:force_style='BackColour=&H70000000,BorderStyle=4,Outline=1,Shadow=0,MarginV=10'" video1+sstit2.mp4

La partie filter_complex "subtitles=video1.ass:force_style='BackColour=&H70000000,BorderStyle=4,Outline=1,Shadow=0,MarginV=10'" gère le détail des options de présentation des sous-titres, comme souvent dans ffmpeg ces options sont délicates à manipuler parce qu'elles agissent au plus bas niveau et sans "garde-fou"; consultez la documentation et agissez avec précaution pour les manipuler, de nombreuses options cont possibles tant sur le texte que sur le fond.

La vidéo produite ne contient aucun flux de sous-titre, le texte est directement incrusté dans les images.

ffprobe video1+sstit2.mp4

.../...

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'video1+sstit2.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf59.27.100
  Duration: 00:09:07.12, start: 0.000000, bitrate: 578 kb/s
  Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1412x830 [SAR 1:1 DAR 706:415], 437 kb/s, 60 fps, 60 tbr, 15360 tbn (default)
    Metadata:
      handler_name    : VideoHandler
      vendor_id       : [0][0][0][0]
      encoder         : Lavc59.37.100 libx264
  Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default)
    Metadata:
      handler_name    : Core Media Audio
      vendor_id       : [0][0][0][0]

6. Conclusion

Cet article présente une des nombreuses façons de sous-titrer une vidéo, la méthode proposée peut certainement être améliorée ou modifiée en fonction de contraintes ou de choix éditoriaux. Un des intérêts est de montrer la faisabilité de l'opération sans qu'il soit besoin de connaissances avancées en media ou en numérique. Il est toutefois parfaitement clair qu'une production qe qualité professionnelle requiert des compétences professionnelles, toutefois il est probable que des étudiants malentendants apprécieront de disposer des sous-titres, de même la possibilité de proposer les sous-titres en anglais ouvre des perspectives importantes.


Commentaires