-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1016 from eleven-labs/feat/codelabs-kotlin-exoplayer
Migrate Créer votre player Netflix avec Exoplayer (codelabs)
- Loading branch information
Showing
5 changed files
with
455 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
--- | ||
contentType: tutorial | ||
lang: fr | ||
date: '2019-08-30' | ||
slug: kotlin-exoplayer | ||
title: Créer votre player Netflix avec Exoplayer | ||
excerpt: >- | ||
Dans ce tutoriel nous allons créer un player android en Kotlin grâce à Exoplayer, pour pouvoir lire une vidéo locale mp4. | ||
categories: | ||
- architecture | ||
authors: | ||
- babas | ||
keywords: | ||
- android | ||
- kotlin | ||
steps: | ||
- introduction | ||
- creation-du-player | ||
- creation-ui | ||
- gestion-des-etats | ||
--- | ||
|
116 changes: 116 additions & 0 deletions
116
_tutorials/fr/2019-08-30-kotlin-exoplayer/steps/creation-du-player.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
--- | ||
contentType: tutorial-step | ||
tutorial: kotlin-exoplayer | ||
slug: creation-du-player | ||
title: Création du Player | ||
--- | ||
## Création du player Exoplayer : | ||
|
||
### Prérequis : | ||
|
||
Créez un fichier versions.gradle dans le répertoire de votre projet et listez vos dépendances en spécifiant leur version. N'oubliez pas d'y introduire la liste des versions que vous utiliserez dans vos dépendances. | ||
Ici : | ||
|
||
```java | ||
ext { | ||
exoPlayerVersion = '2.9.6' | ||
} | ||
``` | ||
|
||
Dans votre fichier build.gradle applicatif ajoutez en haut : | ||
|
||
apply from: 'versions.gradle' | ||
|
||
Enfin, ajoutez dans votre fichier build.gradle les dépendances à ExoPlayer : | ||
|
||
```java | ||
// exoplayer | ||
implementation "com.google.android.exoplayer:exoplayer-core:$exoPlayerVersion" | ||
implementation "com.google.android.exoplayer:exoplayer-ui:$exoPlayerVersion" | ||
``` | ||
|
||
### En ce qui concerne le Player | ||
|
||
Nous allons créer une classe Player. Cette classe va avoir un rôle de façade sur notre player ExoPlayer pour exécuter toutes nos actions type play, pause, instancier notre player, le configurer en fonction du flux d'entrée... | ||
|
||
Pour commencer nous allons créer une variable privé de type SimpleExoPlayer et l'initialiser dans notre objet : | ||
|
||
```java | ||
class Player(val context: Context) { | ||
|
||
private var player: SimpleExoPlayer = ExoPlayerFactory.newSimpleInstance(context) | ||
|
||
} | ||
``` | ||
|
||
À partir d'ici, nous avons notre player instancié. Maintenant il faut lui permettre de lire des vidéos locales. Nous allons donc créer une méthode qui va lui permettre de décoder notre fichier video. ExoPlayer est capable de lire un nombre assez conséquent de formats vidéos différents, que ce soient des vidéos locales ou des streams live. Pour différencier ces types de flux d'entrées nous devons créer un fichier de type MediaSource, qui est le media final que nous passerons à notre player ExoPlayer pour qu'il le lise. Pour créer ce fichier, nous devons passer par une des factories ExoPlayer, qui différera en fonction du flux. À savoir qu'en entrée, la factory va demander une URI. | ||
|
||
Ici j'ai choisi de lire un fichier MP4, format considéré comme standard par exoplayer : | ||
```java | ||
private fun buildMediaSource(uri: Uri): MediaSource { | ||
val factorymediaSourceFactory: ExtractorMediaSource.Factory = | ||
ExtractorMediaSource.Factory( | ||
DefaultDataSourceFactory( | ||
context, | ||
Util.getUserAgent(context, "MyNetflix") | ||
) | ||
) | ||
return factorymediaSourceFactory.createMediaSource(uri) | ||
} | ||
``` | ||
Nous avons notre player, notre MediaSource résultant de la transformation de notre URI. Mais il nous manque un dernier détail... Pour pouvoir s'afficher correctement, ExoPlayer a besoin qu'on lui fournisse une SurfaceView, custom view de la librairie Exoplayer sur laquelle il va pouvoir afficher son contenu. | ||
Nous allons donc pour l'instant ajouter une méthode pour fournir à notre objet Player une surfaceView : | ||
|
||
```java | ||
fun setVideoSurface(surfaceview: SurfaceView) { | ||
player.setVideoSurfaceView(surfaceview) | ||
} | ||
``` | ||
|
||
Enfin bien sûr, nous allons ajouter plusieurs actions, pour pouvoir tester notre super player par la suite. | ||
|
||
Pour charger notre média : | ||
|
||
```java | ||
fun prepare(uri: Uri) { | ||
player.prepare(buildMediaSource(uri), false, true); | ||
} | ||
``` | ||
|
||
Pour reset notre player : | ||
|
||
```java | ||
fun stop() { | ||
player.stop(true) | ||
player.seekToDefaultPosition() | ||
} | ||
``` | ||
|
||
Pour lancer la lecture : | ||
|
||
```java | ||
fun play() { | ||
player.playWhenReady = true | ||
} | ||
``` | ||
|
||
Pour le mettre en pause : | ||
|
||
```java | ||
fun pause() { | ||
player.playWhenReady = false | ||
} | ||
``` | ||
|
||
Et un getter sur son état en lecture ou pas : | ||
|
||
```java | ||
fun isPlaying() { | ||
return player.playWhenReady | ||
} | ||
``` | ||
|
||
À savoir que pour indiquer que l'on veut jouer la vidéo de notre player, il faut modifier la valeur du boolean playWhenReady. ExoPlayer écoute cette valeur. Dès qu'elle est modifiée et s'il n'est pas en cours d'initialisation il lancera instantanément la vidéo. Sinon il attendra de finir son initialisation puis la lancera. |
122 changes: 122 additions & 0 deletions
122
_tutorials/fr/2019-08-30-kotlin-exoplayer/steps/creation-ui.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
--- | ||
contentType: tutorial-step | ||
tutorial: kotlin-exoplayer | ||
slug: creation-ui | ||
title: Création de l'UI | ||
--- | ||
|
||
## Création de notre vue PlayerView : | ||
|
||
Créez un fichier player_view.xml dans le dossier layout de votre projet. | ||
Dans ce fichier nous allons ajouter une SurfaceView, réceptacle de notre player, et un bouton play/pause qui permettra de lancer/arrêter le flux : | ||
|
||
```xml | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
android:layout_width="match_parent" | ||
android:layout_height="match_parent" | ||
xmlns:app="http://schemas.android.com/apk/res-auto"> | ||
|
||
<SurfaceView | ||
android:id="@+id/surface_view" | ||
android:layout_width="400dp" | ||
android:layout_height="300dp" | ||
app:layout_constraintBottom_toBottomOf="parent" | ||
app:layout_constraintLeft_toLeftOf="parent" | ||
app:layout_constraintRight_toRightOf="parent" | ||
app:layout_constraintTop_toTopOf="parent" /> | ||
|
||
<androidx.appcompat.widget.AppCompatImageButton | ||
android:id="@+id/play_pause_button" | ||
style="?android:attr/borderlessButtonStyle" | ||
android:layout_width="wrap_content" | ||
android:layout_height="wrap_content" | ||
android:background="@drawable/exo_controls_play" | ||
app:layout_constraintBottom_toBottomOf="parent" | ||
app:layout_constraintEnd_toEndOf="parent" | ||
app:layout_constraintStart_toStartOf="parent" | ||
app:layout_constraintTop_toTopOf="parent" /> | ||
|
||
</androidx.constraintlayout.widget.ConstraintLayout> | ||
``` | ||
Ensuite nous allons créer une classe PlayerView qui héritera de FrameLayout, dans laquelle on va définir différents comportements, notamment la gestion de l'état du bouton play/pause, son logo, et les actions que ce bouton va effectuer. | ||
|
||
```java | ||
class PlayerView @JvmOverloads constructor( | ||
context: Context, | ||
attrs: AttributeSet? = null, | ||
defStyleAttr: Int = 0 | ||
) : FrameLayout(context, attrs, defStyleAttr) { | ||
|
||
init { | ||
inflate(context, R.layout.player_view, this) | ||
} | ||
} | ||
``` | ||
|
||
On va y initialiser notre PlayerManager : | ||
|
||
```java | ||
private lateinit var playerManager: PlayerManager | ||
|
||
private fun initPlayer() { | ||
playerManager = PlayerManager(context = context) | ||
playerManager.setVideoSurface(surface_view) | ||
playerManager.prepare(Uri.parse("file:/android_asset/example_video.mp4")) | ||
} | ||
``` | ||
|
||
Et dans notre bloc init, on va exécuter notre initPlayer puis définir un listener sur notre bouton pour modifier l'icône et ainsi nous permettre d'avoir un retour UX entre nos lectures et nos pauses : | ||
|
||
À savoir que des ressources sont mises à disposition par la librairie pour avoir des images de contrôles ISO sur tout les players, les ressources exo_controls_play et exo_controls_pause sont donc accessibles sans avoir à ajouter d'icônes dans votre projet. | ||
|
||
```java | ||
init { | ||
inflate(context, R.layout.player_view, this) | ||
|
||
play_pause_button.setOnClickListener { | ||
if (playerManager.isPlaying()) { | ||
playerManager.pause() | ||
play_pause_button.setBackgroundResource(R.drawable.exo_controls_play) | ||
} else { | ||
playerManager.play() | ||
play_pause_button.setBackgroundResource(R.drawable.exo_controls_pause) | ||
} | ||
} | ||
initPlayer() | ||
} | ||
``` | ||
|
||
### Ressources : | ||
|
||
Niveau ressourcee, créez un dossier assets dans votre dossier main à coté des dossiers res et java et mettez y vos ressources vidéos. | ||
Ainsi vous pourrez y accéder dans vos tests comme défini plus haut : | ||
|
||
"file:/android_asset/example_video.mp4" | ||
|
||
### Tests : | ||
|
||
Afin de tester, créer une MainActivity. Dans son layout activity_main définissez un PlayerView comme bon vous semble niveau format : | ||
|
||
```xml | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
xmlns:app="http://schemas.android.com/apk/res-auto" | ||
xmlns:tools="http://schemas.android.com/tools" | ||
android:layout_width="match_parent" | ||
android:layout_height="match_parent" | ||
tools:context=".MainActivity"> | ||
|
||
<com.example.mynetflix.PlayerView | ||
android:id="@+id/player" | ||
android:layout_width="match_parent" | ||
android:layout_height="match_parent" | ||
app:layout_constraintBottom_toBottomOf="parent" | ||
app:layout_constraintLeft_toLeftOf="parent" | ||
app:layout_constraintRight_toRightOf="parent" | ||
app:layout_constraintTop_toTopOf="parent" /> | ||
|
||
</androidx.constraintlayout.widget.ConstraintLayout> | ||
``` | ||
|
||
Si tout s'aligne bien, vous pouvez exécuter votre code et lancer votre application ! |
Oops, something went wrong.