\section{Cadre du projet}

La mission s'inscrivait dans le cadre de la diffusion d'un flux vidéo vers un
chromecast. Il s'avère que le chromecast ne supporte pas de recevoir des flux de
sous-titre, ou alors certains formats seulement. Ceci parce qu'il était à la
base prévu pour Youtube qui n'est jamais très loin du format Webm.

Le webm est un format utilisant une sous-partie du format Matroska, en étant
spécialement dédié à la diffusion de vidéo sur le web et dans un navigateur.

% TODO: expliquer demuxage
L'idée pour intégrer les sous-titres lors de la diffusion est donc de démuxer
les fichiers, puis de rendre ces sous-titres avant directement sur la vidéo
avant de remuxer puis envoyer au chromecast, le tout en temps réel.

Lors de la diffusion d'une vidéo depuis un téléphone, on tombe alors sur un
nouveau problème: l'usage de la batterie. Décoder et réencoder de la vidéo
consomme beaucoup de CPU et le téléphone finit par chauffer et se décharger très
vite.

On peut alors utiliser plutôt les circuits d'encodage intégrés sur presque tous
les téléphones. Ces derniers consomment beaucoup moins d'énergie que leur
pendant logiciel, mais leurs fonctionnalités sont matériellement figées dans les
circuits qui les composent. Ils sont également limités en nombre de sessions
possible, et peuvent avoir des comportements différents entre chaque téléphone
ou faire crasher le programme, voire le téléphone en cas d'utilisation
incorrecte.

% TODO: reference MediaCodec
Pour les téléphones Android, c'est l'API MediaCodec
\footnote{\url{https://developer.android.com/reference/android/media/MediaCodec}}
qu'il faut utiliser afin de manipuler les décodeurs/encodeurs disponibles sur le
téléphone. Un décodeur MediaCodec étant déjà existant, il s'agit plus ou moins
d'étendre les fonctionnalités déjà en place pour pouvoir également instancier un
encodeur.

Dans cette partie-là, nous allons voir ce qu'est un encodeur, comment ils sont
construits et utilisés au sein de VLC ainsi que quelques détails de
l'implémentation finale de l'encodeur utilisant l'API MediaCodec d'Android.

\section{Qu'est-ce qu'un encodeur}

L'encodeur est le module qui récupère des images dans un format fixé et produit
un bytestream vidéo correspondant au format d'encodage vidéo choisi. Il se situe
donc après les filtres vidéos et avant le muxer. Pour la plupart des formats,
l'encodeur a besoin de données spéciales relative au format utilisé. Pour h264,
il s'agit du SPS et PPS, décrivant les informations communes aux images
encodées.

L'encodeur dans MediaCodec fonctionne comme une machine à état asynchone. Il est
probablement important de noter que l'API n'indique pas qu'elle est thread-safe.
% TODO: rôle dans la chaine avec schéma
% TODO: codec specific data
% TODO: état de l'encodeur
% TODO: flux de données

\section{Fonctionnement d'un encodeur dans VLC}

Dans VLC, l'encodeur est principalement utilisé par un seul module: le module
\og{}transcode\fg{}. À ce jour, il utilise un flux multimédia complet en entrée,
c'est-à-dire plusieurs \og{}elementary streams\fg{} que sont les les sous-titres, les
flux vidéos et les flux audios. Il produit ensuite le même flux multimédia
encodé par un muxer.

% TODO: exemple d'utilisation du module transcode en console

L'encodeur est définit par la structure suivante dans le core de VLC.

\begin{code}{c}{Structure d'un encodeur dans VLC}
struct encoder_t
{
    /* common fields */
    /* ... */
    /* Properties of the input data fed to the encoder */
    es_format_t         fmt_in;

    /* Properties of the output of the encoder */
    es_format_t         fmt_out;

    block_t *           ( * pf_encode_video )( encoder_t *, picture_t * );
    block_t *           ( * pf_encode_audio )( encoder_t *, block_t * );
    block_t *           ( * pf_encode_sub )( encoder_t *, subpicture_t * );

    /* Common encoder options */
    /* ... */
};
\end{code}

La première remarque est que l'encodage se fait de façon asynchrone. En effet,
malgré l'interface ici, le module a la possibilité de renvoyer des
pointeur \inltype{block_t} vers \inltype{NULL} pour indiquer qu'il n'a pas fini
de décoder.
% TODO: encodage synchrone : on remplit les pf des types de flux qu'on supporte
% TODO: fmt_in / fmt_out => pas modifiable après ouverture de l'encodeur
% TODO :modifier paragraphe d'apres


\section{Implémentation de l'encodeur}

Des problèmes arrivent dès le début de l'implémentation. Il n'est en effet pas
possible de modifier le format de sortie de l'encodeur après son initialisation
dans la fonction \inltype{OpenEncoder}. Or les informations sur le codec --
codec specific data -- ne sont disponibles qu'après avoir commencé à encoder les
premières images.

L'implémentation que j'ai réalisée fait en sorte de retarder la création du flux
de sortie jusqu'au moment où les premières images encodées sont disponibles. Or,
certains muxeur en sortie ne permettent pas de réaliser ce délai. Des
modifications sur l'architecture étaient donc nécessaires pour l'intégration de
mon travail et étaient en cours à la fin de mon stage.

L'encodeur fonctionne à travers l'API java de MediaCodec, appelé depuis
l'interface JNI. La raison de ce choix est l'impossibilité d'effectuer certaines
actions essentielles à partir de l'interface proposée par le NDK d'android.

Les principales difficultés ont été de:
\begin{itemize}
    \item Comprendre le fonctionnement de l'encodeur dans VLC.
    \item Comprendre les interactions avec le muxer.
    \item Déterminer la façon la plus correcte de définir des PTS et DTS.\@
\end{itemize}

La réalisation du module a été une excellente occasion pour comprendre en
profondeur l'agencement des différents modules du pipeline de VLC.
