Mit einem Vorschauvideo können Sie Nutzer dazu anregen, einen Deeplink zu Ihrer TV-App zu verwenden. Vorschauen können von kurzen Clips bis hin zu vollständigen Filmtrailern reichen.
Beachten Sie beim Erstellen einer Vorschau die folgenden Richtlinien:
- In einer Vorschau dürfen keine Anzeigen eingeblendet werden. Wenn Sie Anzeigen clientseitig einfügen, dürfen Sie sie nicht in Vorschauvideos einfügen. Wenn Sie Anzeigen serverseitig einfügen, stellen Sie ein werbefreies Video für Vorschauen bereit.
- Für die beste Qualität sollten Vorschauvideos im Format 16:9 oder 4:3 vorliegen. Empfohlene Größen für Vorschauvideos finden Sie unter Attribute von Videoprogrammen.
- Wenn Vorschauvideo und Poster unterschiedliche Seitenverhältnisse haben, ändert der Startbildschirm das Seitenverhältnis des Posters in das des Videos, bevor die Vorschau abgespielt wird. Das Video wird nicht mit Letterboxing angezeigt. Wenn das Seitenverhältnis des
Posters beispielsweise
ASPECT_RATIO_MOVIE_POSTER(1:1,441) ist, das des Videos aber 16:9, wird das Poster in einen 16:9-Bereich umgewandelt. - Wenn Sie eine Vorschau erstellen, kann der Inhalt öffentlich zugänglich sein oder durch DRM geschützt werden. In beiden Fällen gelten unterschiedliche Verfahren. Auf dieser Seite werden beide beschrieben.
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 Ihr Video DRM-geschützt ist oder einen Medientyp hat, der von
ExoPlayer nicht unterstützt wird, verwenden Sie einen TvInputService. Der Android TV-Startbildschirm übergibt Ihrem Dienst eine
Surface, indem er onSetSurface() aufruft. Ihre App zeichnet
das Video direkt auf dieser Oberfläche von onTune() aus.
Durch das direkte Rendern auf der Oberfläche kann Ihre App steuern, was und wie gerendert wird. Sie können Metadaten wie die Kanalzuordnung überlagern.
TvInputService im Manifest deklarieren
Ihre App muss eine Implementierung von TvInputService bereitstellen, damit der Startbildschirm Ihre Vorschau rendern kann.
Fügen Sie in die Dienstdeklaration einen Intent-Filter ein, der
TvInputService als Aktion angibt, die mit dem Intent ausgeführt werden soll. Deklarieren Sie außerdem die Dienstmetadaten als separate XML-Ressource. Die Dienstdeklaration, der Intent-Filter und die Deklaration der Dienstmetadaten sind im folgenden Beispiel 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 Datei mit den Dienstmetadaten befindet sich im XML-Ressourcenverzeichnis Ihrer App und muss mit dem Namen der Ressource übereinstimmen, die Sie im Manifest deklariert haben. Wenn Sie die Manifesteinträge aus dem vorherigen Beispiel verwenden, erstellen Sie eine XML-Datei unter res/xml/previewinputservice.xml mit einem leeren tv-input-Tag:
<?xml version="1.0" encoding="utf-8"?>
<tv-input/>
Dieses Tag ist für das TV Input Framework erforderlich. Es wird jedoch nur zum Konfigurieren von Live-Kanälen verwendet. Da Sie ein Video rendern, sollte das Tag leer sein.
Video-URI erstellen
Wenn Ihr Vorschauvideo von Ihrer App und nicht vom Android TV-Startbildschirm gerendert werden soll, müssen Sie einen Video-URI für ein PreviewProgram erstellen.
Der URI sollte mit der ID enden, die Ihre App für den Inhalt verwendet, damit Sie den Inhalt später im TvInputService abrufen können.
Wenn Ihre ID 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 Ihre 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();
Ihre App ruft
onTune(Uri videoUri)
auf, damit Android TV das Vorschauvideo startet.
Dienste erstellen
Im folgenden Beispiel wird gezeigt, wie Sie TvInputService erweitern, um einen eigenen PreviewInputService zu erstellen. Der Dienst verwendet einen MediaPlayer für die Wiedergabe, aber in Ihrem Code kann ein beliebiger Videoplayer verwendet werden.
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
}
}
}