Mit einem Vorschauvideo können Sie Nutzer dazu bewegen, per Deeplink zu Ihrer TV-App zu gelangen. Vorschauen können von kurzen Clips bis hin zu vollständigen Filmtrailern reichen.
Beachten Sie beim Erstellen einer Vorschau die folgenden Richtlinien:
- Keine Anzeigen in der Vorschau anzeigen. Wenn Sie Anzeigen clientseitig zusammenfügen, sollten Sie sie nicht in Vorschauvideos einfügen. Wenn Sie Anzeigen serverseitig platzieren, stellen Sie ein werbefreies Video zur Vorschau bereit.
- Für eine optimale Qualität sollten Vorschauvideos das Format 16:9 oder 4:3 haben. Die empfohlenen Größen für Vorschauvideos finden Sie unter Videoprogrammattribute.
- Wenn das Vorschauvideo und das Poster unterschiedliche Seitenverhältnisse haben, wird die Posteransicht auf dem Startbildschirm auf das Seitenverhältnis des Videos angepasst, bevor die Vorschau wiedergegeben wird.
Das Video hat kein Letterbox-Bild. Wenn das Postergrafik-Verhältnis beispielsweise
ASPECT_RATIO_MOVIE_POSTER
(1:1,441) beträgt, das Videoverhältnis aber 16:9 ist, wird die Posteransicht in einen Bereich von 16:9 umgewandelt. - Wenn Sie eine Vorschau erstellen, kann deren Inhalt öffentlich zugänglich sein oder durch digitale Rechteverwaltung geschützt sein. Für jeden Fall gelten unterschiedliche Verfahren. Auf dieser Seite werden beide behandelt.
Vorschau auf dem Startbildschirm abspielen
Wenn Sie eine Vorschau mit einem der von ExoPlayer unterstützten Videotypen erstellen und die Vorschau öffentlich zugänglich ist, können Sie sie direkt auf dem Startbildschirm abspielen.
Wenn Sie ein PreviewProgram erstellen, verwenden Sie setPreviewVideoUri()
mit einer öffentlich zugänglichen HTTPS-URL, wie im folgenden Beispiel gezeigt. Die Vorschau kann entweder Video oder Audio sein.
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));
Vorschau auf einer Oberfläche rendern
Wenn dein Video DRM-geschützt ist oder in einem Medientyp ist, der von ExoPlayer nicht unterstützt wird, verwende einen TvInputService
.
Der Android TV-Startbildschirm übergibt Surface
durch Aufrufen von onSetSurface()
an Ihren Dienst. Deine App zeichnet Videos von onTune()
direkt auf dieser Oberfläche.
Mit dem direkten Oberflächenrendering kann Ihre App steuern, was gerendert wird und wie dies gerendert wird. Du kannst Metadaten wie die Kanalzuordnung einblenden.
„TvInputService“ im Manifest deklarieren
Deine App muss eine Implementierung von TvInputService
bereitstellen, damit die Vorschau auf dem Startbildschirm gerendert werden kann.
Fügen Sie in die Dienstdeklaration einen Intent-Filter ein, der TvInputService
als die mit dem Intent auszuführende Aktion angibt. Deklarieren Sie außerdem die Dienstmetadaten als separate XML-Ressource. Im folgenden Beispiel werden die Dienstdeklaration, der Intent-Filter und die Deklaration der Dienstmetadaten dargestellt:
<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>
Definieren Sie die Dienstmetadaten in einer separaten XML-Datei.
Die Dienstmetadatendatei befindet sich im XML-Ressourcenverzeichnis für Ihre Anwendung und muss mit dem Namen der Ressource übereinstimmen, die Sie im Manifest deklariert haben. Mithilfe der Manifesteinträge aus dem vorherigen Beispiel würden Sie unter res/xml/previewinputservice.xml
eine XML-Datei mit einem leeren tv-input
-Tag erstellen:
<?xml version="1.0" encoding="utf-8"?>
<tv-input/>
TV Input Framework muss dieses Tag haben. Sie dient jedoch nur zur Konfiguration von Livekanälen. Da du ein Video renderst, sollte das Tag leer sein.
Video-URI erstellen
Wenn Sie angeben möchten, dass das Vorschauvideo von Ihrer App und nicht vom Android TV-Startbildschirm gerendert werden soll, müssen Sie einen Video-URI für PreviewProgram
erstellen.
Der URI sollte mit der ID enden, die Ihre App für den Inhalt verwendet, sodass Sie den Inhalt später im TvInputService
abrufen können.
Wenn Ihre Kennung vom Typ Long
ist, verwenden Sie 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();
Wenn die ID nicht vom Typ Long
ist, erstellen Sie den URI mit 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();
Über die App wird onTune(Uri videoUri)
aufgerufen, damit Android TV das Vorschauvideo startet.
Dienst erstellen
Das folgende Beispiel zeigt, wie Sie TvInputService
erweitern, um eine eigene PreviewInputService
zu erstellen. Der Dienst verwendet MediaPlayer
für die Wiedergabe. Sie können im Code aber jeden verfügbaren Videoplayer verwenden.
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 } } }