{"id":197,"date":"2017-04-18T09:03:58","date_gmt":"2017-04-18T09:03:58","guid":{"rendered":"http:\/\/renaudguezennec.eu\/?p=197"},"modified":"2025-08-17T20:11:52","modified_gmt":"2025-08-17T20:11:52","slug":"mettre-en-ligne-ces-parties","status":"publish","type":"post","link":"http:\/\/renaudguezennec.eu\/index.php\/2017\/04\/18\/mettre-en-ligne-ces-parties\/","title":{"rendered":"Mettre en ligne ses parties !"},"content":{"rendered":"<p>Je suis venu vous conter une histoire. Cette histoire est issue d&#8217;un d\u00e9sir coupable de frimer un peu.<br \/>\nNon, je n&#8217;ai pas r\u00e9ussi \u00e0 faire quelque chose d&#8217;exceptionnel ou d&#8217;impossible comme inventer une ampoule qui dure 10 fois plus longtemps que toutes les autres.<br \/>\nJe souhaite juste montrer comment GNU\/Linux, le syst\u00e8me D et la philosophie OpenSource\/libre\/DIY peuvent permettre d&#8217;automatiser un processus de production vid\u00e9o.<\/p>\n<h2>Contexte:<\/h2>\n<p>Je suis d\u00e9veloppeur de Rolisteam. J&#8217;avais besoin de faire un peu la promotion du logiciel. De plus, en tant que ma\u00eetre de jeu, j&#8217;avais envie de garder une trace de ma campagne, histoire<br \/>\nd&#8217;en faire profiter d&#8217;autres gens.<br \/>\nL&#8217;enregistrement des parties en vid\u00e9o et audio nous a sembl\u00e9 la meilleure solution pour atteindre ces objectifs.<\/p>\n<h2>Le choix des outils:<\/h2>\n<p>Apr\u00e8s une phase de recherche, mon choix s\u2019est port\u00e9 sur:<\/p>\n<h3>SimpleScreenRecorder (SSR)<\/h3>\n<p>Il est pratique, simple et la qualit\u00e9 vid\u00e9o est plut\u00f4t bonne. Le seul probl\u00e8me c&#8217;est l&#8217;enregistrement audio. Impossible d&#8217;enregistrer en m\u00eame temps mon micro et<br \/>\nles voix de mes camarades \u00e0 moins de configurer pulseaudio ou l&#8217;usage de Jack. Je n&#8217;avais pas envie de changer toute la configuration son de ma b\u00e9cane. C\u2019est peut-\u00eatre facile \u00e0 faire mais j\u2019avais pas envie de me lancer la dedans. De plus, la qualit\u00e9 audio de SSR est moins bonne que Teamspeak (je trouve en tout cas).<\/p>\n<h3>Teamspeak:<\/h3>\n<p>Ok, ce n&#8217;est pas libre mais pour des raisons de qualit\u00e9 et d&#8217;habitude des joueurs, on est rest\u00e9 sur cette solution pour l&#8217;audio.<br \/>\nLes fruits de l\u2019enregistrement<\/p>\n<p>Gr\u00e2ce \u00e0 ces outils, j&#8217;ai r\u00e9alis\u00e9 les enregistrements.<br \/>\nJ&#8217;avais donc un fichier son et une vid\u00e9o par partie. Dans un premier temps, j&#8217;ai fusionn\u00e9 les deux fichiers avec ffmpeg pour obtenir la vid\u00e9o de la partie (avec le son).<\/p>\n<pre>ffmpeg -i video.mp4 -i audio.wav -c:v copy -c:a aac -strict experimental output.mp4<\/pre>\n<h2>Am\u00e9liorer l\u2019exp\u00e9rience visuelle<\/h2>\n<p>Souhaitant offrir une meilleure exp\u00e9rience pour les \u00e9ventuels spectateurs, j&#8217;ai cod\u00e9 un plugin \u00e0 teamspeak qui envoie sur dbus le statut de la voix de chaque joueur.<\/p>\n<p>J&#8217;ai cr\u00e9e une application qui \u00e9coute ces messages dbus, quand le joueur parle, le portrait de son personnage s&#8217;affiche en couleur. Quand il est silencieux le portrait du personnage s&#8217;affiche en niveau de gris. Il m&#8217;a fallu plusieurs tests et \u00e9tapes pour arriver \u00e0 ce fonctionnel final.<br \/>\nLes joueurs ne voulant pas montrer leur visage par webcam. Cela semblait la meilleur solution de suivre facilement les conversations.<\/p>\n<p>Vous trouverez le code ici: <a href=\"https:\/\/github.com\/obiwankennedy\/GameVisualisationHelper\/tree\/cops\/display\">https:\/\/github.com\/obiwankennedy\/GameVisualisationHelper\/tree\/cops\/display<\/a><\/p>\n<p>Cette application a apport\u00e9 une contrainte suppl\u00e9mentaire sur les vid\u00e9os. Le son et l&#8217;image doivent \u00eatre synchronis\u00e9s avec pr\u00e9cision. Ce n\u2019\u00e9tait pas le cas avant car les \u00e9l\u00e9ments de l\u2019\u00e9cran pouvait \u00eatre en avance ou en retard par rapport \u00e0 la voix, il n\u2019y avait aucun rep\u00e8re visuel pour le remarquer.<\/p>\n<h2>Caler le son et l\u2019image<\/h2>\n<p>J&#8217;ai d&#8217;abord pens\u00e9 merger les deux fichiers dans un \u00e9diteur vid\u00e9o.<br \/>\nJ&#8217;ai essay\u00e9 PitiVi, OpenShot et Kdenlive. Les deux premiers agonisent dans d&#8217;atroces souffrances apr\u00e8s le chargement de fichiers sup\u00e9rieurs \u00e0 3h. Kdenlive s&#8217;en sort mieux. Il n&#8217;agonise qu&#8217;une fois sur deux. J\u2019ai install\u00e9 les versions de ma distribution et j\u2019ai fait de report de bug mais je pouvais pas attendre la r\u00e9solution des probl\u00e8mes.<\/p>\n<p>Dans ce contexte, trouver le bon timing pour synchroniser l&#8217;audio sur l&#8217;image, c&#8217;est compliqu\u00e9. Le drag and drop de fichier de 3h fait assez mal aux logiciels d&#8217;\u00e9dition vid\u00e9o. Sans parler de la pr\u00e9cision pour les d\u00e9placements. Bref, pas pratique.<\/p>\n<p>Je me suis dit &#8220;c&#8217;est idiot, il faudrait synchroniser le d\u00e9but de l&#8217;enregistrement de l&#8217;audio et la vid\u00e9o&#8221;.<br \/>\nJe n&#8217;ai pas le code source de Teamspeak mais il est possible de cr\u00e9er un plugin (ou de modifier celui que j&#8217;ai cr\u00e9\u00e9) et j&#8217;ai le code source de SimpleScreenRecorder (SSR).<\/p>\n<p>J&#8217;ai donc d\u00e9cid\u00e9 d&#8217;exposer l&#8217;API de SSR sur DBUS et mon plugin teamspeak envoie des commandes dbus. Vive Dbus !<br \/>\nEn gros, j&#8217;ai \u00e9tudi\u00e9 le code de SSR pour identifier la fonction qui d\u00e9marre l&#8217;enregistrement. J&#8217;ai cr\u00e9\u00e9 la petite tambouille pour l&#8217;exposer (ainsi que la fonction pour mettre l&#8217;enregistrement en pause) sur dbus.<\/p>\n<p>Si vous voulez voir comment faire cela: http:\/\/renaudguezennec.eu\/index.php\/2011\/03\/10\/introduction-a-dbus-avec-qt4\/<\/p>\n<p>Pour le coup, apr\u00e8s quelques essais et des modifications sur l&#8217;ensemble des participants \u00e0 l&#8217;affaire. J&#8217;ai une solution qui tourne bien. Je peux utiliser ffmpeg pour fusionner mes fichiers vid\u00e9os avec le son et cela correspond parfaitement.<\/p>\n<pre>ffmpeg -i video.mp4 -i audio.wav -c:v copy -c:a aac -strict experimental output.mp4<\/pre>\n<h2>Une \u00e9tape d\u2019accomplie<\/h2>\n<p>J&#8217;ai fait un pull request \u00e0 l\u2019auteur de SSR. Mon but \u00e9tait de montrer comment faire car l&#8217;auteur de SSR n&#8217;est pas form\u00e9 \u00e0 Dbus. Il est tr\u00e8s int\u00e9ress\u00e9 mais clairement je n\u2019ai pas le temps de g\u00e9n\u00e9raliser l\u2019usage de Dbus dans SSR, ni lui d\u2019ailleurs.<\/p>\n<p>Ma version est accessible ici : <a href=\"https:\/\/github.com\/obiwankennedy\/ssr\">https:\/\/github.com\/obiwankennedy\/ssr<\/a><br \/>\nMa pull request : <a href=\"https:\/\/github.com\/MaartenBaert\/ssr\/pull\/399\">https:\/\/github.com\/MaartenBaert\/ssr\/pull\/399<\/a><\/p>\n<h2>Montage des g\u00e9n\u00e9riques<\/h2>\n<p>Apr\u00e8s ces \u00e9tapes, j&#8217;ai des vid\u00e9os de mes parties assez brutes. Id\u00e9alement, il me reste \u00e0 ajouter un g\u00e9n\u00e9rique de d\u00e9but et de fin.<\/p>\n<p>Pour le faire, j&#8217;ai fait un programme en QML avec deux animations qui se courent apr\u00e8s. C&#8217;est pas jolie mais cela fait le job. Le g\u00e9n\u00e9rique dure ~10 secondes, je l\u2019ai enregistr\u00e9 avec SSR aussi.<br \/>\nJ&#8217;ai utilis\u00e9 Kdenlive pour caler une musique libre dessus.<\/p>\n<p>A la fin de cette \u00e9tape, j&#8217;ai ma petite vid\u00e9o de g\u00e9n\u00e9rique de d\u00e9but, idem pour le g\u00e9n\u00e9rique de fin et mes \u00e9pisodes (plus de 75).<br \/>\nVous l&#8217;avez compris, l&#8217;\u00e9tape ici est de cr\u00e9er des vid\u00e9os contenant les g\u00e9n\u00e9riques.<br \/>\nJ&#8217;ai cherch\u00e9 un peu dans ffmpeg pour arriver \u00e0 cela. C&#8217;est une simple fonction de concat\u00e9nation des vid\u00e9os.<br \/>\nJ&#8217;ai \u00e9crit ma petite commande, \u00e7a marche.<\/p>\n<p>[pastacode lang=&#8221;bash&#8221; manual=&#8221;cd%20%2Fracine%2Fdes%2Fvideos%2F%0AOPENING%3D%2Fchemin%2Fvers%2Fgenerique%2Fdebut.mp4%0AENDING%3D%2Fchemin%2Fvers%2Fgenerique%2Ffin.mp4%0Avideo%3D%2Fchemin%2Fvers%2Fvideos.mp4%0ALIST_FILE%3D%2Ftmp%2Fmylist.txt%0AvideoExtLess%3D%5C%60echo%20%24video%20%7C%20awk%20-F%20&#8242;.&#8217;%20&#8217;%7Bprint%20%241%7D&#8217;%5C%60%0Aecho%20%22file%20&#8217;%24OPENING&#8217;%22%20%3E%20%24LIST_FILE%0Aecho%20%22file%20&#8217;%24video&#8217;%22%20%3E%3E%20%24LIST_FILE%0Aecho%20%22file%20&#8217;%24ENDING&#8217;%22%20%3E%3E%20%24LIST_FILE%0Affmpeg%20-safe%200%20-f%20concat%20-i%20%2Ftmp%2Fmylist.txt%20%24%7BvideoExtLess%7D_avec_generiques.mp4&#8243; message=&#8221;Concat avec ffmpeg&#8221; highlight=&#8221;&#8221; provider=&#8221;manual&#8221;\/]<\/p>\n<p>Du moins, je croyais que cela marchait. En v\u00e9rit\u00e9, cela cassait la synchronisation son\/image. Ce fut tr\u00e8s emb\u00eatant.<br \/>\nJe retourne \u00e0 la case d\u00e9part &#8220;logiciel de montage vid\u00e9o&#8221; (Kdenlive). Il y a un peu moins de manipulation pr\u00e9cise \u00e0 faire. Je colle les trois fichiers: g\u00e9n\u00e9rique de d\u00e9but, l\u2019\u00e9pisode, g\u00e9n\u00e9rique de fin et c&#8217;est parti.<br \/>\n\u00c7a a fonctionn\u00e9 un temps.<\/p>\n<h2>Extraction du son et traitement<\/h2>\n<p>Une fois la vid\u00e9o compl\u00e8te avec les g\u00e9n\u00e9riques. J&#8217;en extrait le son pour la diffusion en podcast, vraiment facile avec ffmpeg.<\/p>\n<pre>ffmpeg -i videos.mp4 -codec:a libmp3lame -qscale:a 2 output.mp3<\/pre>\n<p>Avant de sortir l&#8217;\u00e9pisode en podcast, je le re-travaille un peu avec audacity pour supprimer les silences et pour normaliser le son (avec le filtre compresseur du logiciel).<br \/>\nCela raccourcit l\u2019\u00e9pisode d\u2019environ 30 mins et le son est bien meilleur.<\/p>\n<h2>Traitement sur la vid\u00e9o<\/h2>\n<p>Je souhaite effectuer les m\u00eames traitements sur les vid\u00e9os. J&#8217;ai bien lutt\u00e9 pour trouver une solution.<\/p>\n<h3>Normalisation<\/h3>\n<p>Pour la normalisation, j&#8217;ai trouv\u00e9 un petit script python: ffmpeg-normalize.<\/p>\n<pre>ffmpeg-normalize -vu -p normalized-episode40.mp4 Episode_40.mp4<\/pre>\n<p>Supprimer les moments inutiles<\/p>\n<p>Couper la vid\u00e9o quand il y a du silence fut bien plus complexe. Aucun logiciel de montage vid\u00e9o n&#8217;offre de filtre pour cela (je n&#8217;ai pas trouv\u00e9 en tout cas) et j\u2019allais pas le faire \u00e0 la main. Cela m&#8217;aurait pris trop de temps.<\/p>\n<p>J&#8217;ai donc cherch\u00e9 \u00e0 droite \u00e0 gauche et c&#8217;est Ryzz (Merci \u00e0 lui) sur Linuxfr.org qui m&#8217;a envoy\u00e9 vers une bonne piste: MoviePy<\/p>\n<p>Un module python pour faire de l&#8217;\u00e9dition vid\u00e9o. Il y a m\u00eame un exemple utilisant MoviePy pour cr\u00e9er le r\u00e9sum\u00e9 d&#8217;un match de foot gr\u00e2ce au son des supporters.<\/p>\n<p>J&#8217;ai donc cr\u00e9\u00e9 un script python pour couper les silences. J&#8217;en ai profit\u00e9 \u00e9galement ajouter les g\u00e9n\u00e9riques avec MoviePy.<br \/>\nQuand mon script fut pr\u00eat j&#8217;avais d\u00e9j\u00e0 sorti 20 \u00e9pisodes. J&#8217;en avais donc 40 en stock \u00e0 refaire. J&#8217;ai donc lancer le script sur les 40 restant. Apr\u00e8s 3 jours d\u2019ex\u00e9cution. J&#8217;avais<br \/>\ntous mes \u00e9pisodes pr\u00eats.<\/p>\n<p>Si vous souhaitez voir le code du script et des explications techniques:<br \/>\n<a href=\"http:\/\/renaudguezennec.eu\/index.php\/2017\/03\/03\/montage-video-en-python\/\">http:\/\/renaudguezennec.eu\/index.php\/2017\/03\/03\/montage-video-en-python\/<\/a><\/p>\n<p>La r\u00e9duction des silences est moins efficace qu\u2019audacity mais il y a un gain ind\u00e9niable.<\/p>\n<p>Voil\u00e0, le degr\u00e9s maximum que j\u2019ai atteins dans l&#8217;automatisation.<\/p>\n<h2>Aller encore plus loin<\/h2>\n<p>Dans tout ce processus, il me manque encore des choses pour vraiment automatiser toute la cha\u00eene.<\/p>\n<p>Le premier point, c&#8217;est audacity. Il n&#8217;est pas possible d&#8217;utiliser audacity en ligne de commande. Je me suis un peu renseign\u00e9, il y a eu des tentatives mais c&#8217;est tr\u00e8s complexe \u00e0 mettre en place.<br \/>\nJ&#8217;ai regard\u00e9 un peu le code, esp\u00e9rant trouver un moyen d\u2019appliquer les deux filtres dont j\u2019ai besoin. Le code est peu lisible avec des define partout pour diff\u00e9rencier les OS. Bref, un cauchemar \u00e0 maintenir. Du coup, j\u2019h\u00e9site \u00e0 mis mettre vraiment ou rester en \u00e9dition manuelle.<\/p>\n<p>Ensuite, il me reste \u00e0 automatiser la partie \u201cmise en ligne\u201d sur youtube et sur le wordpress.<br \/>\nJe suis certains que c\u2019est possible mais pour l\u2019instant, je n\u2019ai pas pris le temps de le faire.<br \/>\nSi vous voulez voir le r\u00e9sultat:<\/p>\n<p>Le wordpress pour \u00e9couter les \u00e9pisodes: <a href=\"http:\/\/blog.rolisteam.org\/\">http:\/\/blog.rolisteam.org\/<\/a><br \/>\nLa playlist youtube des \u00e9pisodes : <a href=\"https:\/\/www.youtube.com\/playlist?list=PLBSt0cCTFfS5fi3v1LtB9sfeA8opY-Ge1\">https:\/\/www.youtube.com\/playlist?list=PLBSt0cCTFfS5fi3v1LtB9sfeA8opY-Ge1<\/a><br \/>\nLes premiers n\u2019ont pas b\u00e9n\u00e9fici\u00e9 de tous les outils. Il y a clairement une marque de progression dans les \u00e9pisodes jusqu\u2019\u00e0 l\u2019\u00e9pisode 20 environ.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Je suis venu vous conter une histoire. Cette histoire est issue d&#8217;un d\u00e9sir coupable de frimer un peu. Non, je n&#8217;ai pas r\u00e9ussi \u00e0 faire quelque chose d&#8217;exceptionnel ou d&#8217;impossible comme inventer une ampoule qui dure 10 fois plus longtemps que toutes les autres. Je souhaite juste montrer comment GNU\/Linux, le syst\u00e8me D et la [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":198,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_import_markdown_pro_load_document_selector":0,"_import_markdown_pro_submit_text_textarea":"","footnotes":""},"categories":[31,80],"tags":[54,25,51,35,50,52,53,49],"class_list":["post-197","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tips","category-fr","tag-audacity","tag-bash","tag-pyhton","tag-rolisteam","tag-script","tag-son","tag-ssr","tag-video"],"_links":{"self":[{"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/posts\/197","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/comments?post=197"}],"version-history":[{"count":3,"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/posts\/197\/revisions"}],"predecessor-version":[{"id":205,"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/posts\/197\/revisions\/205"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/media\/198"}],"wp:attachment":[{"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/media?parent=197"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/categories?post=197"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/renaudguezennec.eu\/index.php\/wp-json\/wp\/v2\/tags?post=197"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}