PROBLEMATIQUE

Le multimédia prend de plus en plus d'importance, et nous permet beaucoup de plaisirs à voir et à écouter. Mais les fichiers vidéos qu'on peut se procurer ne sont pas toujours dans un format ni dans un état acceptables pour notre usage. Aussi il faut des programmes permettant de modifier ou de réparer ces vidéos. Il existe des programmes graphiques pour ça, souvent payant, mais aussi un programme gratuit multiplateforme et utilisable en console: ffmpeg. Voir ici:
https://ffmpeg.org/

Ce programme ffmpeg très connu est très puissant mais aussi très complexe, avec une multitude d'options nécessitant souvent une connaissance approfondie des techniques vidéos. Il suffit de jeter un coup d'oeil sur sa documentation pour s'en rendre compte:
https://ffmpeg.org/documentation.html

Pour télécharger ffmpeg, c'est ici:
https://ffmpeg.org/download.html
Sous Windows, il ne s'installe pas: on le désarchive, et on le met où on veut sur le disque. Dans les codes ci-dessous, on précisera bien sûr l'adresse exacte des exécutables utilisés (ffmpeg et ffprobe).

Je ne prétends pas en être un spécialiste! Je dois peut-être en utiliser moins de 5% de ses possibilités, mais j'ai sélectionné quelques lignes de commande avec les bonnes options, qui couvrent la grand majorité de mes besoins. Si vous avez d'autres besoins, il vous sera facile d'adapter les codes ci-dessous.


PRESENTATION GENERALE

Comme je n'aime pas écrire des lignes de commandes dans la console, j'ai préparé des "lanceurs" en Python pour exécuter ffmpeg avec les bonnes options. Ces lanceurs doivent être adaptés au traitement voulu dans un éditeur de texte quelconque (j'utilise spyder), et exécutés ensuite avec affichage en console.

Dans ces codes, les données de traitement sont présentées au début du code, et sont les seules informations à modifier. Ce qui suit ces données, c'est la "machinerie" nécessaire au traitement, qui n'a pas besoin d'être modifiée une fois le programme au point.

Le fait d'écrire les options de ffmpeg dans un éditeur de texte plutôt que dans une console est plus qu'un problème de confort: il permet:
- de se rappeler ce qu'on a fait la dernière fois (mémoire entre cessions)
- d'avoir les explications en commentaires sur les options utilisées
- de garder en commentaires des options en réserve pour des cas particuliers

Ceci permet de gagner du temps, même si on n'a pas fait ça depuis 6 mois!

Voilà les 5 traitements dont je me sers le plus souvent:
- Recherche d'informations sur une vidéo
- Conversion d'une vidéo en mp4
- Conversion d'une liste de vidéos en mp4
- Réparation d'une vidéo
- Extraction audio d'une vidéo

Avant, on va décrire quelques fonctions de bibliothèques que tous les codes utilisent, et qui figureront dans un fichier "biblio.py" destiné à être importé.


FONCTIONS DE BIBLIOTHEQUE

Fonction "cejour()"

Date du jour sous le format "jj/mm/aaaa_hh:mm:ss". Simplement utilisée pour avoir la date et l'heure d'un traitement. Surtout utile quand il y a un fichier log qu'on veut conserver.

Fonction "affichedelai(secs)"

Affichage d'un délai connu en secondes, afin de lire plus clairement le délai d'un traitement sous forme "hh:mm:ss.sss". Par exemple, 2748.562 secondes sera affiché comme "45:48.562", qui se lira facilement: 45 minutes et 48.562 secondes.

Méthode "print2(...)"

Méthode issue de la classe "Print2()", pour afficher des informations pendant le traitement, avec en plus, leur enregistrement dans un fichier log si un tel fichier est fourni.

Fonction "execproc(...)"

Exécution dans un sous-processus permettant d'appeler l'exécutable (ici ffmpeg ou ffprobe) avec les bons arguments, et de renvoyer à la fin le statut d'exécution (0 pour ok).

Il s'agit ici d'un codage très inhabituel de Popen de subprocess: "branché" directement sur sys.stdin et sys.stdout, il permet d'avoir un affichage identique à celui qu'on aurait en lançant le programme dans la console, y compris avec l'affichage des couleurs quand il y en a.

Code complet du module "biblio.py" à importer:

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# -*- coding: utf-8 -*-
 
"""
Biliothèque générale
"""
 
import sys
from datetime import datetime
from subprocess import Popen
 
#############################################################################
def cejour(sepdate='/', septemps='_', sepheure=':'):
    """Retourne la date du jour sous le format "jj/mm/aaaa_hh:mm:ss"
       Possibilité de changer les séparateurs
     """
    jour = datetime.today().strftime('%d/%m/%Y_%H:%M:%S')
    return jour.replace('/', sepdate).replace('_', septemps).replace(':', sepheure)
 
#############################################################################
def affichedelai(secs):
    """Retourne une chaîne pour affichage d'un délai exprimé en secondes. Le
       résultat peut comporter jours, heures, minutes et secondes.
       Exemple: 2748.562 sec  => "45:48.562" soit 45 mn et 48.562 sec
       Un éventuel signe négatif est neutralisé dans le calcul mais restitué
       au résultat final
    """
    sign = "" if secs>=0 else "-"
    secs = abs(secs)
    j, r = divmod(secs, 86400) # 86400: 3600x24
    h, r = divmod(r, 3600)
    m, s = divmod(r, 60)
    j, h, m = int(j), int(h), int(m)
    if j>0:
        return "{}{:d}:{:02d}:{:02d}:{:06.3f}".format(sign, j, h, m, s)
    elif h>0:
        return "{}{:02d}:{:02d}:{:06.3f}".format(sign, h, m, s)
    elif m>0:
        return "{}{:02d}:{:06.3f}".format(sign, m, s)
    else:
        return "{}{:6.3f}".format(sign, s)
 
##############################################################################
def execproc(commande, encodage="utf-8", dictenv=None, shell=False):
    """Appelle l'exécutable et ses arguments (commande) dans un processus.
       - commande: ligne de commande (liste ou chaine de caractères)
       - encodage: encodage des sorties du processus (défaut: 'utf-8)
       - dictenv: dict. d'environnement à passer au processus (défaut: None)
       - shell: si True, accepte les instructions console (défaut: False)
       Retourne le statut d'exécution du programme
    """
    with Popen(commande, bufsize=1, stdin=sys.stdin, stdout=sys.stdout,
            stderr=sys.stdout, shell=shell, env=dictenv,
            universal_newlines=True, encoding=encodage, errors='replace')\
            as proc:
 
        while proc.poll() is None: # on attend tant que le programme est actif
            pass
 
        rc = proc.poll() # statut d'exécution du programme terminé
 
    return rc # retourne le statut d'exécution du programme
 
##############################################################################
class Print2:
    """Affiche le déroulement du traitement dans la console
       Si demandé, enregistre sur disque en plus de l'affichage sur la console
    """
 
    #=========================================================================
    def __init__(self, fichierlog="", modw="w", encodage="utf-8",
                                                                affiche=True):
        """Initialise l'affichage et l'ouverture du fichier log (fichierlog)
           - fichierlog: si non vide: nom de fichier log à créer (avec chemin)
           - modw: mode d'écriture du fichierlog. Si 'a': ne détruit pas avant
           - encodage: encodage du fichierlog
           - affiche: si True, affiche sur le périphérique de sortie
        """
        self.flog = None
        if fichierlog:
            try:
                self.flog = open(fichierlog, modw, encoding=encodage)
            except Exception:
                # fichier log donné non conforme ou inaccessible
                self.flog = None # aucun enregistrement ne sera fait
        self.affiche = affiche
 
    #=========================================================================
    def __call__(self, *v):
        """Affiche sur console et enregistre dans le fichier log si demandé
        """
        if self.affiche:
            print(*v, end='\n', flush=True) # affichage périphérique de sortie
        if self.flog:
            # enregistrement sur disque
            print(*v, end='\n', file=self.flog, flush=True)
 
    #=========================================================================
    def ferme(self):
        """Ferme le fichier log s'il existe et qu'il est ouvert
        """
        if self.flog:
            self.flog.close()

PROGRAMMES DE TRAITEMENT VIDEO

Pour mettre au point ces programme en fonction du contexte d'exécution, il ne faudra pas oublier de préciser l'adresse des exécutables "ffmpeg" et "ffprobe".

Information sur une vidéo

Code complet "infos_video.py"
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# -*- coding: utf-8 -*-
""" Donne des informations sur une vidéo donnée
"""
import os
 
##############################################################################
# Données de traitement
 
# fichier vidéo dont on cherche les informations
source = r"\\MULTINET\public\video\clips\Hiromi Uehara\Hiromi - Desire.mp4"
 
# si fichier log => détourne l'affichage console vers le fichier
fichierlog = "" #"infos_video.txt" # si "" => pas de fichier log
 
# arguments:  toutes les valeurs sont des chaînes de caractères
arguments =[
"-hide_banner", # cache la bannière
"-v", "error", # affiche les erreurs
"-select_streams",  "v:0", # 0: 1er flux vidéo
"-show_format", # affiche les infos du format
"-show_streams", # affiche les infos du flux
source # fichier vidéo dont on cherche les informations
]
 
##############################################################################
##############################################################################
# Données de programme
 
programme = r"D:\progsup\ffmpeg\bin\ffprobe.exe"
 
encodage = "utf-8" #"cp1252":windows, "cp850":console DOS, "iso-8859-1":latin-1
 
dictenv = os.environ.copy() # variables d'environnement (possible: None)
 
shell = False # True pour utiliser les instructions spécifiques console
 
# Ajoute le programme à ses arguments
commande = [programme] + arguments
 
if fichierlog:
    commande = commande + ["1>>", fichierlog, "2>&1"] # ">>" pour ajout
    shell = True # True nécessaire pour le détournement vers le fichier log
 
#############################################################################
# Importations
 
import sys
from time import perf_counter # pour calcul du temps de traitement
 
# Importation des fonctions de bibliothèque
from biblio import (cejour, affichedelai, execproc, Print2)
 
#############################################################################
# Exécution
if __name__ == "__main__":
 
    #==========================================================================
    # valide la source
    if not os.path.exists(source):
        print()
        print("Erreur: fichier source non trouvée")
        print()
        _ = input('Tapez "entrée" pour arrêter') # retarde fermeture console
        sys.exit()
 
    #========================================================================
    # lance la fonction d'affichage (et d'enregistrement si demandé)
    print2 = Print2(fichierlog)
 
    #========================================================================
    # Affiche le titre
    print2()
    print2("INFORMATIONS SUR LA VIDEO ({})".format(cejour()))
    print2("Source:", source)
    if fichierlog:
        print2("Fichier log:", fichierlog)
    print2()
 
    #========================================================================
    # ferme le fichier log pour permettre l'affichage de ffmpeg
    print2.ferme()
 
    #==========================================================================
    # Lance le processus de traitement
    tps = perf_counter() # compteur de temps pour le traitement
 
    rc = execproc(commande, encodage, dictenv, shell)
 
    tps = perf_counter()-tps # temps de traitement
 
    #==========================================================================
    # Fin de traitement
    print2 = Print2(fichierlog, "a") # "a" pour continuer avec fichierlog
 
    #==========================================================================
    # Affiche le temps de traitement et le statut d'exécution
    print2()
    print2("Fin du traitement. Statut d'exécution:", rc)
    print2("Temps d'exécution: {}".format(affichedelai(tps)))
    print2()
 
    #==========================================================================
    # ferme le fichier log s'il existe
    print2.ferme()
 
    ##############################################################################
    # Fin d'exécution
    _ = input('Tapez "entrée" pour arrêter') # retarde fermeture console

Conversion d'une vidéo en mp4


Code complet "conversion_mp4.py"
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# -*- coding: utf-8 -*-
""" Convertit en mp4 la vidéo donnée
"""
import os
 
#############################################################################
# Données de traitement
 
# fichier vidéo à convertir
source = r"\\MULTINET\public\video\videos\TV\Brokenwood_2022-04-24.ts"
 
# fichier converti (défaut: dans le répertoire source)
destination = os.path.splitext(source)[0] + ".mp4"
 
sautexiste = True # si True: ne remplace pas la destination existante
 
# si fichier log => détourne l'affichage console vers le fichier
fichierlog = "" #"conversion_mp4.txt" # si "" => pas de fichier log
 
# arguments:  toutes les valeurs sont des chaînes de caractères
arguments =[
"-i", source, # fichier vidéo à convertir
"-hide_banner", # cache la bannière
"-nostdin", # empêche les questions pendant le traitement
"-y", # permet de remplacer un fichier existant sans demander
"-c:v", "libx264", # utilise le pilote vidéo mp4
"-c:a", "aac", # utilise le pilote audio AAC
destination # => fichier mp4 à créer
]
 
"""
Réserve de codes
"-aspect", "2.4",  # changement ratio (cinema:1920:800)
"-aspect", "16:9",  # changement ratio (full HD:1920:1080)
 
"-vf", "scale=1920:800", # change taille et ratio (cinema:1920:800)
"-vf", "scale=-2:800", # change taille sans changer ratio
"-vf", "scale=1920:-2", # change taille sans changer ratio
"-vf", "scale=iw*2:ih", # change taille en utilisant les variables iw et ih
"""
 
#############################################################################
#############################################################################
# Données de programme
 
programme = r"D:\progsup\ffmpeg\bin\ffmpeg.exe"
 
encodage = "utf-8" #"cp1252":windows, "cp850":console DOS, "iso-8859-1":latin-1
 
dictenv = os.environ.copy() # variables d'environnement (possible: None)
 
shell = False # True pour utiliser les instructions spécifiques console
 
# Ajoute le programme à ses arguments
commande = [programme] + arguments
 
if fichierlog:
    commande = commande + ["1>>", fichierlog, "2>&1"] # ">>" pour ajout
    shell = True # True nécessaire pour le détournement vers le fichier log
 
#############################################################################
# Importations
 
import sys
from time import perf_counter # pour calcul du temps de traitement
 
# Importation des fonctions de bibliothèque
from biblio import (cejour, affichedelai, execproc, Print2)
 
#############################################################################
# Exécution
if __name__ == "__main__":
 
    #==========================================================================
    # valide la source
    if not os.path.exists(source):
        print()
        print("Erreur: Fichier source non trouvé")
        print()
        _ = input('Tapez "entrée" pour arrêter') # retarde fermeture console
        sys.exit()
    source = os.path.abspath(os.path.expanduser(source))
 
    #==========================================================================
    # valide la destination
    if sautexiste and os.path.exists(destination):
        print()
        print("La destination existe déjà")
        print()
        _ = input('Tapez "entrée" pour arrêter') # retarde fermeture console
        sys.exit()
    destination = os.path.abspath(os.path.expanduser(destination))
 
    #========================================================================
    # lance la fonction d'affichage (et d'enregistrement si demandé)
    print2 = Print2(fichierlog)
 
    #========================================================================
    # Affiche le titre
    print2()
    print2("CONVERSION VIDEO EN MP4 ({})".format(cejour()))
    print2("Source:", source)
    print2("Destination:", destination)
    if fichierlog:
        print2("Fichier log:", fichierlog)
    print2()
 
    #========================================================================
    # ferme le fichier log pour permettre l'affichage du processus
    print2.ferme()
 
    #==========================================================================
    # Lance le processus de traitement
    tps = perf_counter() # compteur de temps pour le traitement
 
    rc = execproc(commande, encodage, dictenv, shell)
 
    tps = perf_counter()-tps # temps de traitement
 
    #==========================================================================
    # Réouvre le fichier log pour poursuivre l'enregistrement
    print2 = Print2(fichierlog, "a") # "a" pour continuer fichierlog
 
    #==========================================================================
    # Affiche le temps de traitement et le statut d'exécution
    print2()
    print2("Fin du traitement. Statut d'exécution:", rc)
    print2("Temps d'exécution: {}".format(affichedelai(tps)))
    print2()
 
    #==========================================================================
    # ferme le fichier log s'il existe
    print2.ferme()
 
    ##############################################################################
    # Fin d'exécution
    _ = input('Tapez "entrée" pour arrêter') # retarde fermeture console
Conversion d'une liste de vidéos en mp4

Code complet "conversion_mp4_multi.py"
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# -*- coding: utf-8 -*-
"""Convertit en mp4 les fichiers vidéo qui satisfont les motifs wildcard
"""
import os
 
##############################################################################
# Données de traitement
 
# répertoire source
repsrce = r"\\MULTINET\public\video\videos\TV"
 
# répertoire destination (si "" => même répertoire que le répertoire source)
repdest = r""
 
# motifs wildcard des fichiers sources à convertir (séparateur = ';')
inclusfics = "*.avi;*.mkv;*.mpg;*.mpeg;*.divx;*.vob;*.ts"
 
sautexiste = True # si True: ne remplace pas la destination existante
 
# si fichier log => détourne l'affichage console vers le fichier
fichierlog = "" # "conversion_mp4_multi.txt" # si "" => pas de fichier log
 
arguments = lambda ficsrce, ficdest: [
"-i", ficsrce, # fichier vidéo à convertir
"-hide_banner", # cache la bannière
"-nostdin", # empêche les questions pendant le traitement
"-y", # permet de remplacer un fichier existant sans demander
"-c:v", "libx264", # utilise le pilote vidéo mp4
"-c:a", "aac", # utilise le pilote audio AAC
ficdest # => fichier mp4 à créer
]
 
"""
Réserve de codes
"-aspect", "1920:800",  # changement aspect (cinema:1920:800)
 
"-vf", "scale=1920:800", # change taille et ratio (cinema:1920:800)
"-vf", "scale=-2:800", # change taille sans changer ratio
"-vf", "scale=1920:-2", # change taille sans changer ratio
"-vf", "scale=iw*2:ih", # change taille en utilisant les variables iw et ih
"""
 
##############################################################################
##############################################################################
# Données de programme
 
programme = r"D:\progsup\ffmpeg\bin\ffmpeg.exe"
 
encodage = "utf-8" #"cp1252":windows, "cp850":console DOS, "iso-8859-1":latin-1
 
dictenv = os.environ.copy() # variables d'environnement (possible: None)
 
shell = False # True pour utiliser les instructions spécifiques console
 
#############################################################################
# Importations
 
import sys
from time import perf_counter # pour calcul du temps de traitement
from glob import iglob
 
from biblio import (cejour, affichedelai, execproc, Print2)
 
#############################################################################
if __name__ == "__main__":
 
    #==========================================================================
    # valide le répertoire source
    if not os.path.exists(repsrce):
        print()
        print("Erreur: répertoire source non trouvé")
        print()
        _ = input('Tapez "entrée" pour arrêter') # retarde fermeture console
        sys.exit()
    repsrce = os.path.abspath(os.path.expanduser(repsrce))
 
    #==========================================================================
    # valide le répertoire destination
    if not repdest:
        repdest = repsrce
    if not os.path.exists(repdest):
        os.mkdir(repdest) # crée le répertoire destination
    repdest = os.path.abspath(os.path.expanduser(repdest))
 
    #========================================================================
    # lance la fonction d'affichage (et d'enregistrement si demandé)
    print2 = Print2(fichierlog)
 
    #========================================================================
    # Affiche le titre
    print2()
    print2("CONVERSION DE VIDEOS EN MP4 ({})".format(cejour()))
    print2("Répertoire source:", repsrce)
    print2("Répertoire destination:", repdest)
    print2("Motifs wildcard de recherche:", inclusfics)
    if fichierlog:
        print2("Fichier log:", fichierlog)
    print2()
 
    #==========================================================================
    # cherche tous les fichiers correspondant aux motifs de recherche
 
    fichiers = []
    for motif in inclusfics.split(";"):
        for fichier in iglob(os.path.join(repsrce, motif)):
            if os.path.isfile(fichier):
                fichiers.append(fichier)
 
    #==========================================================================
    # traite tous les fichiers un par un
 
    tps0 = 0 # compteur de temps pour l'ensemble des vidéos
 
    for fichiersrce in fichiers:
 
        #==========================================================================
        # calcule le fichier destination
        nomfic = os.path.basename(fichiersrce) # chemin retiré
        fichierdest = os.path.join(repdest, os.path.splitext(nomfic)[0]+".mp4")
 
        if sautexiste and os.path.exists(fichierdest):
            print2()
            print2("="*79)
            print2("Ce fichier destination existe déjà:", fichierdest)
            print2()
            continue # => fichier suivant
 
        #==========================================================================
        # Affiche le titre pour chaque vidéo
        print2()
        print2("="*79)
        print2("Source:     ", fichiersrce)
        print2("Destination:", fichierdest)
        print2()
 
        #==========================================================================
        # Calcule la ligne de commande
        commande = [programme] + arguments(fichiersrce, fichierdest)
 
        #==========================================================================
        # redirige l'affichage console vers le fichier log si demandé
        if fichierlog:
            commande = commande + ["1>>", fichierlog, "2>&1"]
            shell = True # nécessaire pour la redirection
 
        #========================================================================
        # ferme le fichier log pour permettre l'affichage du processus
        print2.ferme()
 
        #==========================================================================
        # Lance le processus de traitement
        tps = perf_counter() # compteur de temps pour le traitement
 
        rc = execproc(commande, encodage, dictenv, shell)
 
        tps = perf_counter()-tps # temps de traitement
        tps0 += tps
 
        #==========================================================================
        # Réouvre le fichier log pour poursuivre l'enregistrement
        print2 = Print2(fichierlog, "a") # "a" pour continuer fichierlog
 
        #==========================================================================
        # Fin de traitement de la vidéo
        print2()
        print2("Fin du traitement de la vidéo. Statut d'exécution:", rc)
        print2("Temps d'exécution: {}".format(affichedelai(tps)))
        print2()
 
    #==========================================================================
    # Fin de traitement pour l'ensemble des vidéos
    print2()
    print2("="*79)
    print2("Fin du traitement des vidéos")
    print2("Temps total d'exécution: {}".format(affichedelai(tps0)))
    print2()
 
    #==========================================================================
    # ferme le fichier log s'il existe
    print2.ferme()
 
    ##############################################################################
    # Fin d'exécution
    _ = input('Tapez "entrée" pour arrêter') # retarde fermeture console
Réparation d'une vidéo

Code complet "repare_video.py"
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# -*- coding: utf-8 -*-
""" Répare la vidéo donnée
"""
import os
 
#############################################################################
# Données de traitement
 
# Fichier source à réparer
source = r"\\MULTINET\public\video\clips\Ben Heppner - Jules Massenet - Le Cid - O Souverain.mp4"
 
# Fichier destination réparé
destination = r"\\MULTINET\public\video\clips\Ben Heppner - Jules Massenet - Le Cid - O Souverain_ok.mp4"
 
sautexiste = False # si True: ne remplace pas la destination existante
 
# si fichier log => détourne l'affichage console vers le fichier
fichierlog = "" #"repare_video.txt" # si "" => pas de fichier log
 
# arguments:  toutes les valeurs sont des chaînes de caractères
arguments =[
"-i", source, # fichier à réparer
"-hide_banner", # cache la bannière
"-nostdin",  # empêche les questions pendant le traitement
"-y", # permet de remplacer un fichier existant sans demander
"-c:v", "copy", # recopie le flux vidéo
"-c:a", "copy", # recopie le flux audio
destination # => fichier réparé
]
 
#############################################################################
#############################################################################
# données de programme
 
programme = r"D:\progsup\ffmpeg\bin\ffmpeg.exe"
 
encodage = "utf-8" #"cp1252":windows, "cp850":console DOS, "iso-8859-1":latin-1
 
dictenv = os.environ.copy() # variables d'environnement (possible: None)
 
shell = False # True pour utiliser les instructions spécifiques console
 
# Ajoute le programme à ses arguments
commande = [programme] + arguments
 
if fichierlog:
    commande = commande + ["1>>", fichierlog, "2>&1"] # ">>" pour ajout
    shell = True # True nécessaire pour le détournement vers le fichier log
 
#############################################################################
# Importations
 
import sys
from time import perf_counter # pour calcul du temps de traitement
 
# Importation des fonctions de bibliothèque
from biblio import (cejour, affichedelai, execproc, Print2)
 
#############################################################################
# Exécution
if __name__ == "__main__":
 
    #==========================================================================
    # valide la source
    if not os.path.exists(source):
        print()
        print("Erreur: Fichier source non trouvé")
        print()
        _ = input('Tapez "entrée" pour arrêter') # retarde fermeture console
        sys.exit()
    source = os.path.abspath(os.path.expanduser(source))
 
    #==========================================================================
    # valide la destination
    if sautexiste and os.path.exists(destination):
        print()
        print("La destination existe déjà")
        print()
        _ = input('Tapez "entrée" pour arrêter') # retarde fermeture console
        sys.exit()
    destination = os.path.abspath(os.path.expanduser(destination))
 
    #========================================================================
    # lance la fonction d'affichage et d'enregistrement (si demandé)
    print2 = Print2(fichierlog)
 
    #========================================================================
    # Affiche le titre
    print2()
    print2("REPARATION VIDEO ({})".format(cejour()))
    print2("Source:", source)
    print2("Destination:", destination)
    if fichierlog:
        print2("Fichier log:", fichierlog)
    print2()
 
    #========================================================================
    # ferme le fichier log pour permettre l'affichage du processus
    print2.ferme()
 
    #==========================================================================
    # Lance le processus de traitement
    tps = perf_counter() # compteur de temps pour le traitement
 
    rc = execproc(commande, encodage, dictenv, shell)
 
    tps = perf_counter()-tps # temps de traitement
 
    #==========================================================================
    # Réouvre le fichier log pour poursuivre l'enregistrement
    print2 = Print2(fichierlog, "a") # 'a' pour continuer fichierlog
 
    #==========================================================================
    # Affiche le temps de traitement et le statut d'exécution
    print2()
    print2("Fin du traitement. Statut d'exécution:", rc)
    print2("Temps d'exécution: {}".format(affichedelai(tps)))
    print2()
 
    #==========================================================================
    # ferme le fichier log s'il existe
    print2.ferme()
 
    ##############################################################################
    # Fin d'exécution
    _ = input('Tapez "entrée" pour arrêter') # retarde fermeture console
Extraction audio d'une vidéo

Code complet "extrait_audio.py"
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# -*- coding: utf-8 -*-
""" Extrait l'audio d'une vidéo donnée
"""
import os
 
##############################################################################
# Données de traitement
 
# fichier vidéo à extraire
source = r"\\MULTINET\public\video\clips\Hiromi Uehara\Hiromi - Suite Escapism  in Between.mp4"
 
# fichier audio extrait
destination = r"\\MULTINET\public\music\Hiromi\Hiromi - Suite Escapism  in Between_3.mp3"
 
sautexiste = False # si True: ne remplace pas la destination existante
 
canalaudio = 0 # numéro canal audio à extraire  (0 => 1er canal audio)
 
# si fichier log => détourne l'affichage console vers le fichier log
fichierlog = "" #"extrait_audio.txt" # si "" => pas de fichier log
 
# arguments:  toutes les valeurs sont des chaînes de caractères
arguments =[
"-i", source, # source fichier video
"-hide_banner", # cache la bannière
"-nostdin", # empêche les questions pendant le traitement
"-y", # permet de remplacer un fichier existant sans demander
"-map", "0:a:"+str(canalaudio), # => copie canal audio
destination # fichier audio destination (mp3, aac, ...)
]
 
"""
Réserve de codes
"-c", "copy", # extrait audio sans réencodage
"-map", "0:a", # sélectionne tous les canaux audio
"""
 
##############################################################################
##############################################################################
# données de programme
 
programme = r"D:\progsup\ffmpeg\bin\ffmpeg.exe"
 
encodage = "utf-8" #"cp1252":windows, "cp850":console DOS, "iso-8859-1":latin-1
 
dictenv = os.environ.copy() # variables d'environnement (possible: None)
 
shell = False # True pour utiliser les instructions spécifiques console
 
# Ajoute le programme à ses arguments
commande = [programme] + arguments
 
if fichierlog:
    commande = commande + ["1>>", fichierlog, "2>&1"] # ">>" pour ajout
    shell = True # True nécessaire pour le détournement vers le fichier log
 
#############################################################################
# Importations
 
import sys
from time import perf_counter # pour calcul du temps de traitement
 
# Importation des fonctions de bibliothèque
from biblio import (cejour, affichedelai, execproc, Print2)
 
#############################################################################
# Exécution
if __name__ == "__main__":
 
    #==========================================================================
    # valide la source
    if not os.path.exists(source):
        print()
        print("Erreur: Fichier source non trouvé")
        print()
        _ = input('Tapez "entrée" pour arrêter') # retarde fermeture console
        sys.exit()
    source = os.path.abspath(os.path.expanduser(source))
 
    #==========================================================================
    # valide la destination
    if sautexiste and os.path.exists(destination):
        print()
        print("La destination existe déjà")
        print()
        _ = input('Tapez "entrée" pour arrêter') # retarde fermeture console
        sys.exit()
    destination = os.path.abspath(os.path.expanduser(destination))
 
    #========================================================================
    # lance la fonction d'affichage et d'enregistrement (si demandé)
    print2 = Print2(fichierlog)
 
    #========================================================================
    # Affiche le titre
    print2()
    print2("EXTRACTION AUDIO D'UNE VIDEO ({})".format(cejour()))
    print2("Source:", source)
    print2("Destination:", destination)
    if fichierlog:
        print2("Fichier log:", fichierlog)
    print2()
 
    #========================================================================
    # ferme le fichier log pour permettre l'affichage de ffmpeg
    print2.ferme()
 
    #==========================================================================
    # Lance le processus de traitement
    tps = perf_counter() # compteur de temps pour le traitement
 
    rc = execproc(commande, encodage, dictenv, shell)
 
    tps = perf_counter()-tps # temps de traitement
 
    #==========================================================================
    # Réouvre le fichier log pour poursuivre l'enregistrement
    print2 = Print2(fichierlog, "a") # "a" pour continuer avec fichierlog
 
    #==========================================================================
    # Affiche le temps de traitement et le statut d'exécution
    print2()
    print2("Fin du traitement. Statut d'exécution:", rc)
    print2("Temps d'exécution: {}".format(affichedelai(tps)))
    print2()
 
    #==========================================================================
    # ferme le fichier log s'il existe
    print2.ferme()
 
    ##############################################################################
    # Fin d'exécution
    _ = input('Tapez "entrée" pour arrêter') # retarde fermeture console

EXEMPLE D'EXPLOITATION

On place les 6 codes (5 codes de traitement + code de la bibliothèque) dans le même répertoire appelé, par exemple, "utilvideos".

J'utilise Spyder comme outil de développement (https://pypi.org/project/spyder/). Pour rendre son utilisation plus facile, je conseille la configuration suivante:
- afficher les "fichiers" pour pouvoir naviguer dans l'arborescence des fichiers du disque
- définir la console de l'OS (cmd.exe pour Windows) comme périphérique de sortie.

Avec Spyder, on crée sur le bureau un raccourci qui lance:
/chemin/vers/spyder - p /chemin/vers/utilvideos

Après un double-clic sur le raccourci, Spyder se charge, et affiche le répertoire "utilvideos" et son contenu. Un double-clic sur le nom du code souhaité le fera venir dans l'éditeur de texte. Après édition et enregistrement des données de traitement, il suffira de cliquer sur l'icone d'exécution, et tout se déroulera dans la console. Avec la mémoire du fichier log s'il a été déclaré.

Mais, bien sûr, un autre éditeur de texte pourrait convenir! Cependant, attention à "idle" livré avec Python, qui va bien pour l'édition de texte, mais pas pour l'exécution à cause de l'affichage dans la console interne.

J'ai développé et j'utilise tout ça sous Windows, mais il y a peu de codes spécifiques, aussi il est hautement probable que ça fonctionne aussi sous les "unix" (linux, macOS), ou avec un peu d'adaptation. Que ceux qui essaient donnent ici le résultat de leur tentative!


Bons traitements vidéos !