Philippe Gibert

Développeur FullStack

Derniers posts

Comment construire un transcodeur vidéo avec SpringBoot et FFMPEG !

J'ai récemment commencé à travailler sur un système de caméras de surveillance et je souhaite pouvoir afficher les vidéos collectées sur des pages Web. À première vue, cela semblait très facile, mais je me suis vite rendu compte que je devais me creuser la tête!

Comment cela doit fonctionner?

La caméra est connectée à un NVR (Numeric Video recorder) qui possède une API permettant de récupérer les informations de configuration et le flux vidéo. En cherchant un peu sur le Web (Oui la documentation est difficile d'accès..), je découvre que le protocole de communication utilisé par le NVR est le RTSP (Real-Time Streaming Protocol). C'est là que je rencontre le principal problème ! Comment utiliser ce protocole dans une page HTML qui ne le supporte pas ? Ma solution est d'utiliser un serveur qui permet de transcoder la vidéo dans un format plus connu (MP4) et un protocole ultra standard (Http). Cela me permettra également de cacher les identifiants d'accès à la caméra en utilisant mon serveur comme un proxy.

Graph it should work

Alors comment on fait ça?

Un excellent outil bien connu pour faire de la conversion vidéo est FFMPeg, donc je commence à regarder comment je peux l'utiliser pour convertir RSTP. Je trouve rapidement une ligne de commande qui fonctionne :

ffmpeg -y -loglevel level+info -n -re -acodec pcm_s16le -rtsp_transport tcp -i rtsp://user:passwd@192.168.1.200:554/ISAPI/Streaming/channels/101/live -vcodec copy -af asetrate=22050 -acodec aac -b:a 96k -nostdin myvideo.mp4

Alors comment faire un proxy avec SpringBoot ? C'est très simple en fait, il suffit d'utiliser l'objet StreamingResponseBody. Cela permet de renvoyer un traitement asynchrone de la requête, où l'application peut écrire directement sur le flux de sortie de la réponse sans bloquer le reste de mon API.

Enfin, il me suffit d'utiliser FFMPEG dans mon contrôleur pour envoyer le flux via mon API. J'aurais pu utiliser " Runtime.getRuntime().exec(" ffmpeg...) " mais je n'arrivais pas à trouver comment obtenir mon flux. Heureusement, j'ai trouvé une bibliothèque magique Jaffree : "Jaffree stands for JAva FFmpeg and FFprobe FREE command line wrapper. Jaffree supports programmatic video production and consumption (with transparency)"

La solution

Voici la solution finale et comment relayer un flux vidéo provenant d'une caméra HikVision afin que le format soit utilisable par une page HTML.

import com.github.kokorin.jaffree.StreamType;
import com.github.kokorin.jaffree.ffmpeg.FFmpeg;
import com.github.kokorin.jaffree.ffmpeg.PipeOutput;

@RestController
@RequestMapping("/video")
@Log4j2
public class VideoController {
    @GetMapping(value = "/live.mp4")
    @ResponseBody
    public ResponseEntity<StreamingResponseBody> livestream(@PathVariable("id") Long tipperId) throws Exception {

        String rtspUrl = "rtsp://user:passwd@192.168.1.200:554/ISAPI/Streaming/channels/101/live";

        return ResponseEntity.ok()
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(os -> {
                    FFmpeg.atPath()
                            .addArgument("-re")
                            .addArguments("-acodec", "pcm_s16le")
                            .addArguments("-rtsp_transport", "tcp")
                            .addArguments("-i", $rtspUrl)
                            .addArguments("-vcodec", "copy")
                            .addArguments("-af", "asetrate=22050")
                            .addArguments("-acodec", "aac")
                            .addArguments("-b:a", "96k" )
                            .addOutput(PipeOutput.pumpTo(os)
                                    .disableStream(StreamType.AUDIO)
                                    .disableStream(StreamType.SUBTITLE)
                                    .disableStream(StreamType.DATA)
                                    .setFrameCount(StreamType.VIDEO, 100L)
                                     //1 frame every 10 seconds
                                    .setFrameRate(0.1)
                                    .setDuration(1, TimeUnit.HOURS)
                                    .setFormat("ismv"))
                            .addArgument("-nostdin")
                            .execute();
                });

    }
}

Vous devrez également modifier la configuration de votre application SpringBoot (fichier application.properties) pour augmenter le délai d'attente pour les requêtes asynchrones.

spring.mvc.async.request-timeout = 3600000

Il vous suffit d'appeler votre API sur la page web :

<div class="video">
  <video width="100%" height="auto" controls autoplay muted loop *ngIf="event?.video">
    <source src="http://localhost:8080/video/live.mp4"
            type="video/mp4">
    Sorry, your browser doesn't support embedded videos.
  </video>
</div>

Et voici le résultat :

Final result

Facile non?

Retrouvez l'article anglais sur dev.to


Android Emulator sur Apple Silicon, enfin une preview!

Bonsoir à tous!

J'ai récemment craqué pour le nouveau MacBook Pro M1! Depuis 1 semaine que je l'apprivoise, toutes les applications que j'utilise fonctionnent (merci Rosetta2!). Mon seul problème, en tant que developpeur mobile, est que l'Emulateur Android ne fonctionne pas. C'est d'ailleurs le problème de toutes les applications qui font de la virtualisation (Docker, ParallelDesktop, etc …)! Je dois donc utiliser un téléphone physique, et cela m'empêche de tester mes applications sur différentes versions d'Android.

Heureusement les ingénieurs de Google sont à fond sur le coup et ont mis à disposition une version Preview de l'émulateur ici : https://androidstudio.googleblog.com/2020/12/android-emulator-apple-silicon-preview.html

Et ça fonctionne :

Capture Android preview

Pour autant tout n'est pas parfait :

  • Les Webview ne fonctionnent pas
  • Pas de son
  • Pas de skin téléphone
  • Les codecs vidéos ne sont pas fonctionnels
  • Les applications ARM 32Bits ne sont pas compatibles
  • Quelques bugs graphiques sur les applications utilisant l'API Vulkan
  • Une popup apparait au démarrage de l'émulateur, indiquant qu'elle ne trouve pas ADB

Tout est dit! Il ne reste plus qu'à tester 😃.

Amusez-vous bien!


Comment bien configurer son serveur Postgres avec PGTune

Récemment, j'ai dû mettre le nez dans les serveurs de notre application, car nous avions des problèmes de performances et de stabilité.

Pour vous replanter le décor, l'application dont je m'occupe aujourd'hui est hébergé sur un serveur qui comprend un service de base de données Postgres, un serveur d'application Java, ainsi que d'un serveur apache permettant aux utilisateurs de télécharger le front. Tout ça fonctionne sur le même serveur sans conteneurs. N'ayant pas installé ces services moi-même, j'ai dû passer un peu de temps pour comprendre pourquoi notre serveur plantait lors de fortes charges... Puis je me suis aperçu grâce à notre système de monitoring que la mémoire du serveur Postgres n'était même pas limitée...

Je n'ai aucune connaissance sur les configurations des services Postgres, et comme je n'aime pas trop perdre de temps à éplucher les documentations, j'ai fouillé un peu sur la toile. C'est là que j'ai découvert le travail de Alexey Vasiliev (@leOpard) qui propose un générateur de configuration Postgres : PGTune

Il suffit de paramétrer votre configuration en fonction des ressources que vous voulez allouer sur le serveur! Et PAF ça fait le ☕!

PGTune capture

Il ne vous reste plus qu'à injecter cette nouvelle configuration dans le fichier de configuration de votre Postgres.

Depuis que j'ai appliqué la configuration par l'utilitaire, je n'ai plus de problème de performance. Finalement, les utilisateurs sont contents, et moi aussi 😃.

Pour les fans de Ruby, où si cela vous amuse, vous pouvez aller consulter le code du générateur de @leOpard, les sources sont disponibles sur Github : https://github.com/le0pard/pgtune


Giboow, le Blog!

Je m'appelle Philippe, j'ai 36 ans, j'ai une petite famille ainsi qu'un chat et deux poules! Je suis développeur d'application depuis une bonne quinzaine d'années. Le développement et la technologie occupent donc une bonne partie de mes journées !

J'ai toujours aimé la programmation et la logique qui en découle. J'ai commencé ma carrière au collège en 4e, lorsque mon grand frère m'a offert une calculatrice Casio graphique, depuis ce jour là j'ai découvert les bases de la programmation ! À 13 ans, nous avons reçu notre premier ordinateur, c'était un Apple Performa 6320, au bout d’un mois nous avons démonté la bête avec mon frère pour voir comment cela fonctionnait ! J'ai ensuite continué mon évolution tranquillement avec des pages HTML statiques, des Apple script, etc...

Pendant mes études j'ai beaucoup travaillé sur Linux j'ai donc une bonne connaissance de ce système et de son fonctionnement, je ne suis cependant pas un expert (mais je me débrouille toujours 😃).

En 2009, j'ai commencé ma carrière professionnelle. J'ai toujours voulu naviguer sur différents projets, apprendre de nouvelles choses. Je déteste le fait d'être considéré comme un expert dans une technologie précise. J'aime apprendre de nouvelles choses, maitriser l'ensemble de mes projets, et de partager mes connaissances avec mes amis, mes collègues, vous !

Sur ce blog conçut et réaliser avec ♥, je vais essayer de vous partager mon quotidien (du code, du code, du code!!), mais aussi tout ce que je trouve intéressant sur la toile et relatif a mon métier (application, librairies, hardware, news, etc.) !

Ce site va être aussi pour moi, un bon moyen pour (re)découvrir ReactJs ainsi que NextJs. J'ai en effet eu l'occasion de manipuler ces deux frameworks, mais sans jamais proposer une version disponible publiquement.