{{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]]