Une vidéo d'aperçu est un excellent moyen d'encourager les utilisateurs à accéder directement à votre application TV. Les aperçus peuvent aller de courts extraits à des bandes-annonces de films complets.
Lorsque vous créez un aperçu, tenez compte des consignes suivantes :
- N'affichez pas d'annonces dans un aperçu. Si vous insérez des annonces côté client, ne les insérez pas dans les vidéos d'aperçu. Si vous insérez des annonces côté serveur, fournissez une vidéo sans publicité pour les aperçus.
- Pour une qualité optimale, les vidéos d'aperçu doivent être au format 16:9 ou 4:3. Consultez Attributs de programme vidéo pour connaître les tailles recommandées des vidéos d'aperçu.
- Lorsque la vidéo d'aperçu et l'affiche ont des formats différents, l'écran d'accueil redimensionne l'affiche au format de la vidéo avant de lire 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 le format de la vidéo est 16:9, l'affiche est transformée en une région 16:9. - Lorsque vous créez un aperçu, son contenu peut être accessible au public ou protégé par DRM. Différentes procédures 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éos compatibles avec ExoPlayer et que l'aperçu est accessible au public, vous pouvez le lire directement sur l'écran d'accueil.
Lorsque vous créez un PreviewProgram, utilisez setPreviewVideoUri() avec une URL HTTPS accessible au public
, comme illustré dans l'exemple suivant. L'aperçu peut être
soit une vidéo soit un contenu 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 dans un type de média non compatible avec
ExoPlayer, utilisez un TvInputService. L'écran d'accueil Android TV transmet un
Surface à votre service en appelant onSetSurface(). Votre application dessine
la vidéo directement sur cette surface à partir de onTune().
Le rendu direct sur une surface permet à votre application de contrôler ce qui est rendu et comment. Vous pouvez superposer des métadonnées telles que l'attribution de la chaîne.
Déclarer votre TvInputService dans le fichier manifeste
Votre application doit fournir une implémentation de TvInputService pour que l'écran d'accueil
puisse afficher votre aperçu.
Dans la déclaration de votre service, incluez un filtre d'intent qui spécifie
TvInputService comme action à effectuer avec l'intent. Déclarez également les métadonnées du service en tant que ressource XML distincte. La déclaration de service, le filtre d'intent et la déclaration de métadonnées de service sont présenté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 des ressources XML de votre application et doit correspondre au nom de la ressource que vous avez déclarée dans le fichier manifeste. En utilisant les entrées de fichier manifeste de l'exemple précédent, vous créeriez un fichier XML dans res/xml/previewinputservice.xml, avec un tag tv-input vide :
<?xml version="1.0" encoding="utf-8"?>
<tv-input/>
TV Input Framework doit comporter ce tag. Toutefois, il n'est utilisé que pour configurer les chaînes en direct. Étant donné que vous affichez une vidéo, le tag doit être vide.
Créer un URI vidéo
Pour indiquer que votre vidéo d'aperçu doit être affichée par votre application plutôt que par l'écran d'accueil Android TV, vous devez créer un URI vidéo pour un PreviewProgram.
L'URI doit se terminer par l'identifiant que votre application utilise pour le contenu, afin que vous puissiez le récupérer ultérieurement dans le 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 à l'aide
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 démarre la vidéo d'aperçu.
Créer un service
L'exemple suivant montre comment étendre TvInputService pour créer votre propre 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/<id>
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/<id>
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
}
}
}