Générer un fichier MP4

Le logiciel couramment utilisé dans les pipelines pour générer des fichiers vidéos est FFmpeg. Derrière ces quelques lettres peu sexys se cache un monstre du logiciel libre.

Se lancer dans l’écriture d’une ligne de commande FFmpeg s’apparente à calligraphier un Flaubert; le doute vous assaillie rapidement. :petrus:

Voici une ligne de commande qui convertit une séquence EXR en MP4 :

ffmpeg -colorspace bt709 -color_primaries bt709 -apply_trc bt709 -i ma_sequence.$04d.exr -f mp4 -pix_fmt yuv420p -colorspace bt709 -color_primaries bt709 -color_trc bt709 ma_sequence.mp4

Les arguments avant la séquence d’entrée (avant « -i ») spécifient les paramètre de la séquence EXR :

  • colorspace bt709
  • color_primaries bt709
  • apply_trc bt709

Le dernier vient demander à FFmpeg d’appliquer une transformation de couleur vers bt709. Votre EXR, en linéaire, est donc convertis en Rec. 709.

Notez que FFmpeg utilise le nom des standards. Si cela ne pose pas de problèmes pour BT/Rec/ITU 709 (il y a 709 dedans…), sachez que pour du sRGB, il faut utiliser la valeur « iec61966_2_1 », IEC 61966-2-1 étant le nom du standard définissant sRGB. Plus d’informations ici.

Dans le cas des paramètres de sortis (après « -i »), c’est presque identique :

  • colorspace bt709
  • color_primaries bt709
  • color_trc bt709

Le dernier explicitant, ce coup-ci, la transformation de couleur utilisé dans l’image.

Si vous utilisez ffprobe, vous devriez obtenir quelque chose qui ressemble à ça :

$ ffprobe ma_sequence.mp4
...
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'ma_sequence.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf57.83.100
  Duration: 00:00:03.28, start: 0.000000, bitrate: 3995 kb/s
    Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p(tv, bt709), 1024x540 [SAR 1:1 DAR 512:270], 3992 kb/s, 24 fps, 24 tbr, 12800 tbn, 48 tbc (default)
...

On voit donc que le flux vidéo est en bt709.

Au passage, durant l’écriture de ce billet, je suis tombé sur le site de John Van Sickle qui compile des builds de FFmpeg pour Linux, merci à lui. :sourit:

Comportement de mrViewer

mrViewer s’appuie sur OpenColorIO avec le profile nuke-default qui contient les informations de la plupart des espaces colorimétriques de notre industrie.

Pourtant, quand on ouvre notre MP4 8 bits, mrViewer ne semble pas s’intéresser à ce qu’il y a dedans.

[img] ma_sequence.mp4 - Got colorspace 'sRGB' from bitdepth 8 bits as default

Mais d’où sort-il son sRGB ? :bete:

Quand on lit les préférences utilisateurs de mrViewer (Dans .filmaura/mrViewer.prefs sous Linux), on trouve ceci :

[./ui/view/ocio/ICS]

8bits:sRGB
16bits:
32bits:
float:

Une première méthode consiste donc à remplacer « sRGB » par « rec709 » directement dans ce fichier.

Bien que faisable, ce n’est pas forcément optimal : Pouvoir déterminer le profile colorimétrique suivant ce qu’on cherche à afficher (playblast, séquence d’images EXR/JPEG, texture) nécessite de devoir modifier ce paramètre à chaque fois qu’on lance mrViewer. :pasClasse:

La question reste donc en suspend : Où mrViewer définit-il sRGB comme profile colorimétrique des fichiers 8 bits par défaut ? :perplex:

On pourrait envoyer un mail à Gonzalo Garramuño (qui maintient ce logiciel et le fait évoluer depuis presque dix ans !!!), mais quand on a un égo disproportionné comme le mien, on prend le code, on cherche le message d’erreur dedans (« Got colorspace ») et on le lit. :grenadelauncher:

Après quelques minutes de lecture, je me retrouvais avec pas mal de noms de variables que le code semblait utiliser comme si elles étaient initialisés, sans que je ne retrouve jamais l’endroit ou elles étaient définies. :gne2:

Je ne vais pas vous faire un passage en revue du code, mais le morceau qui va nous intéresser est celui-là :

    fltk::Preferences ics( ocio, "ICS" );
    {
#define OCIO_ICS(x, d)							\
        ok = ics.get( #x, tmpS, d, 2048 );                              \
        CMedia::ocio_##x##_ics = environmentSetting( "MRV_OCIO_" #x "_ICS" , \
                                                     tmpS, ok );	\
        uiPrefs->uiOCIO_##x##_ics->text( tmpS );

          OCIO_ICS( 8bits,  "sRGB" );
          OCIO_ICS( 16bits, "" );
          OCIO_ICS( 32bits, "" );
          OCIO_ICS( float,  "" );

    }

Fichtre ! Une macro ! :mechantCrash:

Ce bout de code initialise les préférences; pour chaque appel à la macro OCIO_ICS(), il « exécute » (« duplique » serait plus approprié) un bout de code. Par exemple, le premier appel (« OCIO_ICS(8bits, "sRGB") ») donnera :

ok = ics.get("8bits", tmpS, "sRGB", 2048);
CMedia::ocio_8bits_ics = environmentSetting("MRV_OCIO_8bits_ICS", tmpS, ok);
uiPrefs->uiOCIO_8bits_ics->text(tmpS);

Pour expliquer brièvement, ics est une section des préférences, enfant de la variable ocio, portant de nom "ICS" (Input Color Space je suppose). Cette section se retrouve dans les préférences (« [./ui/view/ocio/ICS] », voir plus haut).

La première ligne prend, dans cette section ics, la variable défini à la clef « 8bits » qu’il met dans tmpS (une variable défini plus haut « char  tmpS[2048]; » pour stocker temporairement une valeur). Si cette clef n’existe pas (dans le cas d’un premier lancement et que les préférences n’existent pas ou sont vides), il prend la valeur « sRGB ». Le 2048 étant juste la limite de le nombre de lettres maximum que la méthode get() peut stocker dans tmpS. Les codeurs C sont habitués à ce genre de choses (et un xkcd pour la route !).

On comprend donc d’où sort la valeur par défaut. :sauteJoie:

La seconde ligne est la plus intéressante, c’est elle qui défini le contenu des variables dont je parlais plus haut. Si la variable d’environnement existe, il renvoie sa valeur. Si elle n’existe pas, il renvoie la valeur de tmpS.

Et ça c’est un peu le cadeau bonus ! À savoir qu’on peut outrepasser la variable par défaut via une variable d’environnement. :smileFou:

Ainsi, votre code de lancement peut définir le contenu de la variable MRV_OCIO_8bits_ICS à la volée au moment du lancement de mrViewer. :laClasse:

Si vous définissez un environnement d’application en Python il suffit de faire ça :

my_env['MRV_OCIO_8bits_ICS'] = 'rec709'

Et, gratification suprême, la confirmation:

[img] ma_sequence.mp4 - Got colorspace 'rec709' from bitdepth 8 bits as default

Conclusion

Comme je ne sais pas comment conclure ce billet, je vous propose un poème de haute qualité :

De Rec 709 et sRGB
Dépendent les remarques inspirées
D’un réal toutefois blasé
Face à l’art pixelisé
De graphistes fatigués.

Il insista, faussement serein :
« Que ce bleu soit plus myrtille… »
Des déjections dans leurs pupilles
D’autres raisons, il n’en voyait point
Comment personne de goût pouvait trouver reluisant
L’exposition d’un tel néant.

D’un seul homme, une graphiste objecta
« Tu ne parles plus à des incultes aisés
Retire donc tes lunettes teintées
Du soleil, s’il y en a,
C’est le fruit de notre labeur que tu vois
Car de tes choix peu avisés
En faire de l’or est notre métier ».

Un TD qui passait nonchalamment
Remarqua la querelle chimérique
Alors calme et rassurant
Il prit contrôle des périphériques
Puis tût la discorde en sélectionnant
Le bon profil colorimétrique.

:marioCours: