{{tag>vidéo}} {{tag>ffmpeg}} {{tag>srt}} {{tag>Sous-titrage}}{{tag>vobsub2srt}} {{tag>mkvtoolnix}} ====== Extraction des sous-titres d'une vidéo ====== Scripts bash permettant de convertir plusieurs pistes de sous-titre vobsub d'une vidéo enregistrer sur la TNT par exemple et de les convertir en sous-titres texte .srt. L'extraction de sous-titres d'une vidéo multicanal demande d'identifier les canaux sous-titres puis d'effectuer une reconnaissance de caractère pour les transformer en fichiers srt (texte) moins volumineux et plus faciles à inclure dans un fichier vidéo mkv Matroska. ===== Algorithme ===== Inspiré de l'algorithme : [[tutoriel:vobsub_srt|Conversion de sous-titres VobSub en SRT]] Les 3 dernières étapes peuvent être réalisées avec vobsub2srt * Repérer les canaux de sous-titres d'un fichier vidéo avec ffmpeg * extraire sous-titres vobsub dans une vidéos mastroika * extraire les sous-titres des vidéos mastroïka avec mkvextract * convertir fichier .sub et .idx en tiff; * reconnaissance de caractère de chaque tiff avec cunéiform * création d'un fichier srt ==== Script bash correspondant à l'algorithme ==== [[https://raw.githubusercontent.com/albanmartel/dvsub2srt.bash/main/dvsub2srt.bash | dvsub2srt.bash]] # !/bin/bash # OUTPUT-COLORING red=$( tput setaf 1 ) green=$( tput setaf 2 ) NC=$( tput sgr0 ) # or perhaps: tput sgr0 #NC=$( tput setaf 0 ) # or perhaps: tput sgr0 # Dépendances : ffmpeg, mkvtoolnix, vobsub2srt # Signale quel programme l'on exécute # puis la composition du répertoire où le script s'exécute echo -e "programme pour extraire des canaux de sous-titres d'une vidéo\n Composition du répertoire courant :\n $(ls)" # Invite de commande pour entrer le fichier vidéo à traiter echo -n "Entrer le fichier vidéo choisi :"; read film_a_traiter; # Message pour informer l'utilisateur de son choix echo -e "Le fichier vidéo choisi est : \n $film_a_traiter" # Exemple film_a_traiter="RetourVersLeFutur2.mp4" # film_a_traiter="RetourVersLeFutur2.mp4" # soustitres_array= ("4|fra" "5|fra") soustitres_array=($(ffprobe $film_a_traiter -v quiet -show_entries stream=index:stream_tags=language -select_streams s -of compact=p=0:nk=1)) # metadata_sub="-map 0:4 -metadata:s:s:1 language=fra -map 0:5 -metadata:s:s:2 language=fra" metadata_sub=$(for (( c=0; c<${#soustitres_array[@]}; c++)); do echo -map 0:$(echo ${soustitres_array[$c]} | cut -d "|" -f1) -metadata:s:s:$(($c + 1)) language=$(echo ${soustitres_array[$c]} | cut -d "|" -f2) ; done) # command1="ffmpeg -i RetourVersLeFutur2.mp4 -map 0:4 -metadata:s:s:1 language=fra -map 0:5 -metadata:s:s:2 language=fra -c:s dvdsub sous_titres_RetourVersLeFutur2.mp4.mk" command1=$(echo "ffmpeg -i $film_a_traiter $metadata_sub -c:s dvdsub sous_titres_$film_a_traiter.mkv") # Execution commande n°1 $command1 $command1 # vobsub_piste="0:0_ 1:1_" vobsub_piste=$(for (( c=0; c<${#soustitres_array[@]}; c++));do echo $c:$c"_"; done) #command2="mkvextract tracks sous_titres_RetourVersLeFutur2.mp4.mkv -c ISO8859-1 0:0_ 1:1_" command2=$(echo "mkvextract tracks sous_titres_$film_a_traiter.mkv -c ISO8859-1 $vobsub_piste") # Execution commande n°2 $command2 $command2 # Exécution Roc des fichiers de sous-titres #vobsub2srt 0_; vobsub2srt 1_;" for (( c=0; c<${#soustitres_array[@]}; c++)); do vobsub2srt $c"_"; done exit 0; ==== Ancien Exemple de séquence bash correspondant à l'algorithme ==== ffmpeg -i data0003.ts 2>&1 | grep subtitle mkdir data0003 ffmpeg -i data0003.ts -map 0:4 -map 0:5 -vn -an -scodec dvdsub data0003.mkv mkvextract tracks "data0003.mkv" -c ISO8859-1 0:data0003/0_ mkvextract tracks "data0003.mkv" -c ISO8859-1 1:data0003/1_ subp2tiff --sid=0 -n data0003/0_ subp2tiff --sid=1 -n data0003/1_ for eachTiff in data0003/*.tif; do cuneiform -l fra -f text -o $eachTiff.txt $eachTiff; done subptools -s -w -t srt -i data0003/0_.xml -o 0_.srt subptools -s -w -t srt -i data0003/1_.xml -o 1_.srt ==== Exemple de conversion de fichier TS en MKV avec FFMPEG ==== La commande suivante permet d'obtenir l'info : ffmpeg -i 9 pistes : 0:0 vidéo 0:1 ne contenant pas de données 0:2 Audio 0:3 ne contenant pas de données 0:5 Subtite 0:6 subtitle 0:7 piste non reconnue par ffmpeg 0:8 piste non reconnue par ffmpeg ffmpeg -threads 4 -i data0003.ts -map 0:0 -map 0:2 -map 0:5 -map 0:6 -acodec copy -vcodec copy -scodec dvdsub output.mkv //-threads// pour pouvoir utiliser un traitement multiprocesseurs -// map// pour spécifier toutes les pistes à utilisables //-acodec// suivi de //copy// pour le traitements des pistes audio //-vcodec// suivi de //copy// pour le traitement de la piste vidéo // -scodec// suivi de //dvdsub// pour le traitement des sous-titres ===== dépendances à installer ===== **[[apt>ffmpeg]]** - une collection de logiciels libres destinés au traitement de flux audio ou vidéo **[[apt>mkvtoolnix]]** éventuellement aussi **[[apt>mkvtoolnix-gui]]** - un ensemble d'outils permettant de créer, de modifier et d'inspecter des fichiers Matroska **[[apt>vobsub2srt]]** - Commande de reconnaissance optique de caractères multi-langue pour extraire des sous-titres **[[apt>cuneiform]]** - Système de reconnaissance optique de caractères multi-langue **[[apt>ogmrip]]** - Application pour extraire et encoder des DVDs ===== Script ts2srt ===== Script ancien : pas de gestion des erreurs de reconnaissances optiques [[https://raw.githubusercontent.com/albanmartel/ts2srt/master/ts2srt.bash| ts2srt.bash]] # ---------------------------------------------------- # Script''ts2srt'' # ---------------------------------------------------- # Par ''Alban MARTEL'' # Courriel : albanmartel(POINT)developpeur(AT)gmail(POINT)com # Utilisant comme base de travail le script de beguam # https://doc.ubuntu-fr.org/tutoriel/vobsub_srt # License : GNU GPL # Ce script permet d'extraire les sous-titres d'une video TS et de les transformer en SRT éditable. # # Depends : # ffmpeg est une collection de logiciels libres destinés au traitement de flux audio ou vidéo # mkvToolnix (interface graphique pour mkvmerge) est un ensemble d'outils permettant de créer, de modifier et d'inspecter des fichiers Matroska # cuneiform - Système de reconnaissance optique de caractères multi-langue # ogmrip - Application pour extraire et encoder des DVDs # # Date : 26/08/2015 # version : 0.1 # Mise-à-jour : # ---------------------------------------------------- # !/bin/bash # OUTPUT-COLORING red=$( tput setaf 1 ) green=$( tput setaf 2 ) NC=$( tput sgr0 ) # or perhaps: tput sgr0 #NC=$( tput setaf 0 ) # or perhaps: tput sgr0 function readDirectoryPath(){ echo -n "chemin absolu du répertoire des vidéos où extraire les sous-titres : " read directory; courant_directory=$(pwd); if [[ ! -e "$directory" ]]; then echo "incorrect"; readDirectoryPath; fi cd $directory; directory=$(pwd); cd $courant_directory; echo $directory; #testIfAnyFileIsPresent=$(find . -maxdepth 1 -iname "*.$extension" | wc -l); } function presentationOfFileDirectory(){ message=$("<<"$directory">> contient les fichiers suivants : "); files=$(ls $directory/*.*); print "%$\n" "${green}$message${NC}"; print "%$\n" "${green}$files${NC}"; } function readVideoExtension(){ echo -n "Extension des fichiers vidéos à traiter ("$((4-$count))" tentatives restantes) : " read extension; testIfAnyFileIsPresent=$(find $directory -maxdepth 1 -iname "*.$extension" | wc -l); } function choiseTypeOfVideo(){ local tmp_videos="" count=0; readDirectoryPath; presentationOfFileDirectory; testIfAnyFileIsPresent=0; while [ $testIfAnyFileIsPresent = 0 ] && [ $count != 3 ] ; do count=$(($count+1)); readVideoExtension; done if [ $count = 3 ] ; then print "%$\n" "${red}""3 mauvaises tentatives entrainent l\'arrêt du programme""${NC}"; print "%$\n" "${red}""Abandon""${NC}"; exit 100; fi #/home/alban/Vidéos/fr3/annez.ts" | sed "s/\(.*\)\/\([Aa-Zz]*.$extension\)/\2/g" #Example : data0001.ts data0002.ts data0003.ts cd $directory; videoFiles=($( ls *.$extension )); cd $courant_directory; } function cleanVideoInformations() { cat $1 | grep Imput > $2; cat $1 | grep Duration >> $2; cat $1 | grep Stream >> $2; rm $1; } function prepareCommandToObtainSubtitlesTrackNumer(){ local a; #local j=0; for (( i=0 ; i < ${#videoFiles[@]} ; i++ )) ; do #/home/alban/Vidéos/fr3/ENEMY/data0003.ts data_videos_files[i]=$(echo $directory"/"${videoFiles[i]}); #/tmp/data0001_subtitle_infos.txt tmp_video_info[i]=$(echo "/tmp/"${videoFiles[i]} | sed "s/.$extension/_subtitle_infos.txt/g"); #/tmp/data0003.ts.info video_info_file[i]=$(echo /tmp/${videoFiles[i]}.info); #ffprobe /home/alban/Vidéos/fr3/ENEMY/data0003.ts 2>&1 | ffmpeg -i EnnemyMine.ts -vn -an 2>&1 | grep '[A-Z][a-z]\{4\}' | sed "s/\(^[ ]*\)\([[:alnum:]]\)/\2/g" >/tmp/data0001_subtitle_infos.txt ffprobe ${data_videos_files[i]} 2>&1 | grep '[A-Z][a-z]\{4\}' | sed "s/\(^[ ]*\)\([[:alnum:]]\)/\2/g" >${tmp_video_info[i]}; #create a cleanning file of video information cleanVideoInformations "${tmp_video_info[i]}" "${video_info_file[i]}"; #cat /tmp/video-info.txt | grep Subtitle | sed "s/\(^.* \#\)\([0-9]:[0-9]\)(\([[:alnum:]]\{3\}\))\(.*\)/\2#\3/g" # tracks_Info[1] =Stream #0:5(fra): Subtitle: dvd_subtitle (default) Stream #0:6(ger): Subtitle: dvd_subtitle Stream #0:7(fra): Subtitle: dvd_subtitle tracks_Info[i]=$(cat ${video_info_file[i]} | grep Subtitle | sed "s/\(^.* \#\)\([0-9]:[0-9]\)(\([[:alnum:]]\{3\}\))\(.*\)/\2#\3/g" ); rm ${video_info_file[i]}; done } function createDirectoryIfNotExist(){ if [[ ! -e $1 ]] ; then mkdir $1; fi } function ExtractSubtitleFromVideoInMKV(){ local j=0; local k=0; $1 echo 'tracks_Info: '${tracks_Info[@]}; for ((i=0 ; i< ${#tracks_Info[@]}; i++)); do #From : data0001.ts to: data0001 extract_work_files[i]=$(echo ${videoFiles[i]} | sed "s/.$extension//g"); #echo ${directory}/${extract_work_files[i]}; createDirectoryIfNotExist "${directory}/${extract_work_files[i]}"; tmp=($(echo ${tracks_Info[i]})); for each in ${tmp[@]};do # De : 0:4#fra à : 0.4 fra #0:4 track_number=$(echo $each | cut -d'#' -f1); #fra track_lang=$(echo $each | cut -d'#' -f2); #ffmpeg -threads 4 -i /home/alban/Vidéos/fr3/ENEMY/data0001.ts -map 0:5 -vn -an -scodec dvdsub /home/alban/Vidéos/fr3/ENEMY/data0001/data0001_0_fra.mkv ffmpeg -threads 4 -i ${directory}/${videoFiles[i]} -map $track_number -vn -an -scodec dvdsub ${directory}/${extract_work_files[i]}/${extract_work_files[i]}\_$j\_$track_lang.mkv; mkv_files[k]=$(echo ${directory}/${extract_work_files[i]}/${extract_work_files[i]}\_$j\_$track_lang.mkv); mkv_directories[k]=$(echo ${directory}/${extract_work_files[i]}); subtitle_sub_id[k]=$(echo ${extract_work_files[i]}\_$j\_$track_lang); subtitle_lang[k]=$(echo $track_lang); j=$(($j + 1)); k=$(($k + 1)) done done } function OpticalRecognitionCharacterOfTiff(){ for eachTiff in $1*.tif; do cuneiform -l $2 -f text -o $eachTiff.txt $eachTiff; done } function convertMKVSubtitleInSRT(){ local j=0 for (( i=0 ; i < ${#mkv_files[@]}; i++ )); do #mkvextract tracks /home/alban/Vidéos/fr3/EnnemyMine/EnnemyMine_0_fra.mkv -c ISO8859-1 0:/home/alban/Vidéos/fr3/EnnemyMine/EnnemyMine_0_fra mkvextract tracks ${mkv_files[i]} -c ISO8859-1 0:${mkv_directories[i]}/${subtitle_sub_id[i]}; # if sub file existe and has a size equal to 0 than erase sub and idx files if [ ! -s ${mkv_directories[i]}/${subtitle_sub_id[i]}.sub ]; then rm ${mkv_directories[i]}/${subtitle_sub_id[i]}.sub; rm ${mkv_directories[i]}/${subtitle_sub_id[i]}.idx; fi done for (( i=0 ; i < ${#videoFiles[@]} ; i++ )) ; do work_directories=$(echo ${videoFiles[i]} | sed "s/.$extension//g") ; #mkv_directories=$(echo $directory/work_directories kv_directories${videoFiles[i]} | sed "s/.$extension//g"); for each in $directory/$work_directories"/*.idx"; do subtitle_sub=($(echo $each)); for filesub in ${subtitle_sub[@]}; do #id_file=/home/alban/Vidéos/clanDesSabresVollants/de/Le_Secret_des_poignards_Volants_base/Le_Secret_des_poignards_Volants_base__fra id_file=$(echo $filesub | sed "s/.idx//g"); subp2tiff --sid=0 -n $id_file; #fra sub_lang=$(echo $filesub | sed "s/\(.*\)\([a-z]\{3\}\)\(.idx\)/\2/g"); #subtitle_file_name : /home/alban/Vidéos/clanDesSabresVollants/de/Le_Secret_des_poignards_Volants_base/Le_Secret_des_poignards_Volants_base__fra.srt subtitle_file_name=$(echo $filesub | sed "s/.idx//g"); echo "subtitle_file_name : "$subtitle_file_name; #sub_id=$directory/$work_directories$(echo $filesub | sed "s/\(.*\)\(\_[0-9]\_\)\([a-z]\{3\}\)\(.idx\)/\2\3/g"); #OpticalRecognitionCharacterOfTiff "$sub_id" "$sub_lang"; OpticalRecognitionCharacterOfTiff "$subtitle_file_name" "$sub_lang"; #echo $directory/$(echo ${videoFiles[i]} | sed "s/.$extension//g")/; # tmp= Le_Secret_des_poignards_Volants_base__fra tmp=$(echo $filesub | sed "s/\(.*\)\/\(.*\)\(.idx\)/\2/g" ); echo "commande subptools : subptools -s -w -t srt -i $id_file.xml -o $directory/$tmp.srt"; subptools -s -w -t srt -i $id_file.xml -o $directory/$tmp.srt done rm -rf $directory/$work_directories; done done } choiseTypeOfVideo; prepareCommandToObtainSubtitlesTrackNumer; ExtractSubtitleFromVideoInMKV convertMKVSubtitleInSRT; exit 0; ===== Contributeurs ===== [[:utilisateurs:albanmartel]]