Un aperçu vidéo est un excellent moyen d'encourager les utilisateurs à ajouter un lien profond vers votre application TV. Il peut s'agir d'extraits courts ou de bandes-annonces de film complètes.
Lorsque vous créez un aperçu, tenez compte des consignes suivantes:
- Ne pas diffuser d'annonces dans un aperçu Si vous assemblez les annonces côté client, ne les assemblez pas dans des aperçus vidéo. Si vous assemblez les annonces côté serveur, des vidéos sans publicité pour les aperçus.
- Pour une qualité optimale, les aperçus vidéo doivent être au format 16:9 ou 4:3. Voir Attributs des programmes vidéo pour connaître les tailles recommandées pour les aperçus vidéo.
- Lorsque l'aperçu vidéo et l'affiche ont des formats différents,
écran d'accueil redimensionne l'affichage de l'affiche au format de la vidéo avant la lecture de l'aperçu.
La vidéo n'est pas au format letterbox. Par exemple, si
le format de l'affiche est
ASPECT_RATIO_MOVIE_POSTER
(1:1.441) mais que la vidéo est en 16:9, la vue poster se transforme en zone 16:9. - Lorsque vous créez un aperçu, son contenu peut être accessible au public ou protégées par la DRM. Des procédures différentes s'appliquent dans chaque cas. Cette page décrit les deux.
Lire l'aperçu sur l'écran d'accueil
Si vous créez un aperçu à l'aide de l'un des types de vidéo compatible avec ExoPlayer et que l'aperçu est accessible publiquement, vous pouvez le lire directement sur l'écran d'accueil.
Lorsque vous créez un PreviewProgram
utilisez setPreviewVideoUri()
avec un protocole HTTPS
comme indiqué dans l'exemple ci-dessous. L'aperçu peut être :
video ou
audio.
Kotlin
val previewVideoUrl = Uri.parse("https://www.example.com/preview.mp4") val builder = PreviewProgram.Builder() builder.setChannelId(channelId) // ... .setPreviewVideoUri(previewVideoUrl)
Java
Uri previewVideoUrl = Uri.parse("https://www.example.com/preview.mp4"); PreviewProgram.Builder builder = new PreviewProgram.Builder(); builder.setChannelId(channelId) // ... .setPreviewVideoUri(Uri.parse(previewVideoUrl));
Afficher l'aperçu sur une surface
Si votre vidéo est protégée par DRM ou utilise un type de support non compatible avec
ExoPlayer, utilisez un TvInputService
.
L'écran d'accueil d'Android TV transmet un Surface
à votre service
en appelant onSetSurface()
. Votre application dessine des vidéos directement sur cette surface à partir de onTune()
.
Le rendu direct de la surface permet à votre application de contrôler ce qui est affiché et comment il est affiché rendu. Vous pouvez superposer des métadonnées telles que l'attribution de la chaîne.
Déclarer TvInputService dans le fichier manifeste
Votre application doit fournir une implémentation de TvInputService
pour que votre aperçu s'affiche sur l'écran d'accueil.
Dans votre déclaration de service, incluez un filtre d'intent qui spécifie
TvInputService
comme action à effectuer avec la
l'intention. Déclarez également les métadonnées du service en tant que ressource XML distincte. La
la déclaration de service, le filtre d'intent et la déclaration de métadonnées du service sont affichés
dans l'exemple suivant:
<service android:name=".rich.PreviewInputService" android:permission="android.permission.BIND_TV_INPUT"> <!-- Required filter used by the system to launch our account service. --> <intent-filter> <action android:name="android.media.tv.TvInputService" /> </intent-filter> <!-- An XML file which describes this input. --> <meta-data android:name="android.media.tv.input" android:resource="@xml/previewinputservice" /> </service>
Définissez les métadonnées du service dans un fichier XML distinct.
Le fichier de métadonnées du service se trouve dans le répertoire de ressources XML.
pour votre application et doit correspondre au nom de la ressource déclarée dans le
fichier manifeste. En utilisant les entrées du fichier manifeste de l'exemple précédent, vous devez
créez un fichier XML à l'emplacement res/xml/previewinputservice.xml
, avec un fichier
Balise tv-input
:
<?xml version="1.0" encoding="utf-8"?>
<tv-input/>
Le framework d'entrée TV doit comporter cette balise. Toutefois, il n'est utilisé que pour configurer les chaînes en direct. Puisque vous effectuez le rendu d'une vidéo, le tag doit être vide.
Créer un URI vidéo
Pour indiquer que l'aperçu vidéo doit être affiché par votre application plutôt que par
l'écran d'accueil d'Android TV, vous devez créer un URI vidéo pour un PreviewProgram
.
L'URI doit se terminer par l'identifiant utilisé par votre application pour le contenu.
peut récupérer le contenu ultérieurement dans TvInputService
.
Si votre identifiant est de type Long
, utilisez
TvContractCompat.buildPreviewProgramUri():
Kotlin
val id: Long = 1L // content identifier val componentName = new ComponentName(context, PreviewVideoInputService.class) val previewProgramVideoUri = TvContractCompat.buildPreviewProgramUri(id) .buildUpon() .appendQueryParameter("input", TvContractCompat.buildInputId(componentName)) .build()
Java
Long id = 1L; // content identifier ComponentName componentName = new ComponentName(context, PreviewVideoInputService.class); previewProgramVideoUri = TvContractCompat.buildPreviewProgramUri(id) .buildUpon() .appendQueryParameter("input", TvContractCompat.buildInputId(componentName)) .build();
Si votre identifiant n'est pas de type Long
, créez l'URI en utilisant
Uri.withAppendedPath()
:
Kotlin
val previewProgramVideoUri = Uri.withAppendedPath(PreviewPrograms.CONTENT_URI, "content-identifier") .buildUpon() .appendQueryParameter("input", TvContractCompat.buildInputId(componentName)) .build()
Java
previewProgramVideoUri = Uri.withAppendedPath(PreviewPrograms.CONTENT_URI, "content-identifier") .buildUpon() .appendQueryParameter("input", TvContractCompat.buildInputId(componentName)) .build();
Votre application appelle
onTune(Uri videoUri)
pour qu'Android TV lance l'aperçu vidéo.
Créer un service
L'exemple suivant montre comment étendre TvInputService
pour créer le vôtre
PreviewInputService
Notez que le service utilise un MediaPlayer
pour la lecture,
mais votre code peut utiliser
n'importe quel lecteur vidéo disponible.
Kotlin
import android.content.Context import android.media.MediaPlayer import android.media.tv.TvInputService import android.net.Uri import android.util.Log import android.view.Surface import java.io.IOException class PreviewVideoInputService : TvInputService() { override fun onCreateSession(inputId: String): TvInputService.Session? { return PreviewSession(this) } private inner class PreviewSession( internal var context: Context ) : TvInputService.Session(context) { internal var mediaPlayer: MediaPlayer? = MediaPlayer() override fun onRelease() { mediaPlayer?.release() mediaPlayer = null } override fun onTune(uri: Uri): Boolean { // Let the TvInputService know that the video is being loaded. notifyVideoUnavailable(VIDEO_UNAVAILABLE_REASON_TUNING) // Fetch the stream url from the TV Provider database // for content://android.media.tv/preview_program/val id = uri.lastPathSegment // Load your video in the background. retrieveYourVideoPreviewUrl(id) { videoUri -> if (videoUri == null) { Log.d(TAG, "Could not find video $id") notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN) } try { mPlayer.setDataSource(getApplicationContext(), videoUri) mPlayer.prepare() mPlayer.start() notifyVideoAvailable() } catch (IOException e) { Log.e(TAG, "Could not prepare media player", e) notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN) } } return true } override fun onSetSurface(surface: Surface?): Boolean { mediaPlayer?.setSurface(surface) return true } override fun onSetStreamVolume(volume: Float) { // The home screen may fade in and out the video's volume. // Your player should be updated accordingly. mediaPlayer?.setVolume(volume, volume) } override fun onSetCaptionEnabled(b: Boolean) { // enable/disable captions here } } companion object { private const val TAG = "PreviewInputService" } }
Java
import android.content.Context; import android.media.MediaPlayer; import android.media.tv.TvInputService; import android.net.Uri; import android.support.annotation.Nullable; import android.util.Log; import android.view.Surface; import java.io.IOException; public class PreviewVideoInputService extends TvInputService { private static final String TAG = "PreviewVideoInputService"; @Nullable @Override public Session onCreateSession(String inputId) { return new PreviewSession(this); } private class PreviewSession extends TvInputService.Session { private MediaPlayer mPlayer; PreviewSession(Context context) { super(context); mPlayer = new MediaPlayer(); } @Override public boolean onTune(Uri channelUri) { // Let the TvInputService know that the video is being loaded. notifyVideoUnavailable(VIDEO_UNAVAILABLE_REASON_TUNING); // Fetch the stream url from the TV Provider database // for content://android.media.tv/preview_program/String id = uri.getLastPathSegment(); // Load your video in the background. retrieveYourVideoPreviewUrl(id, new MyCallback() { public void callback(Uri videoUri) { if (videoUri == null) { Log.d(TAG, "Could not find video" + id); notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN); } try { mPlayer.setDataSource(getApplicationContext(), videoUri); mPlayer.prepare(); mPlayer.start(); notifyVideoAvailable(); } catch (IOException e) { Log.e(TAG, "Could not prepare media player", e); notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN); } } }); return true; } @Override public boolean onSetSurface(@Nullable Surface surface) { if (mPlayer != null) { mPlayer.setSurface(surface); } return true; } @Override public void onRelease() { if (mPlayer != null) { mPlayer.release(); } mPlayer = null; } @Override public void onSetStreamVolume(float volume) { if (mPlayer != null) { // The home screen may fade in and out the video's volume. // Your player should be updated accordingly. mPlayer.setVolume(volume, volume); } } @Override public void onSetCaptionEnabled(boolean enabled) { // enable/disable captions here } } }