Videovorschau

Ein Vorschauvideo ist eine hervorragende Möglichkeit, Nutzer zu ermutigen, über Deeplinks zu Ihrer TV-App zu gelangen. Die Vorschauen können von kurzen Clips bis hin zu ganzen Filmtrailern reichen.

Beachten Sie beim Erstellen einer Vorschau die folgenden Richtlinien:

  • Keine Anzeigen in der Vorschau einblenden. Wenn Sie auf Clientseite Anzeigen platzieren, fügen Sie sie nicht in Vorschauvideos ein. Wenn Sie Anzeigen serverseitig platzieren, stellen ein werbefreies Video für die Vorschau bereit.
  • Für eine optimale Qualität sollten Vorschauvideos das Seitenverhältnis 16:9 oder 4:3 haben. Weitere Informationen finden Sie unter Attribute für Videoprogramme .
  • Wenn das Vorschauvideo und das Poster unterschiedliche Seitenverhältnisse haben, Startbildschirm passt die Posteransicht vor dem Abspielen der Vorschau an das Seitenverhältnis des Videos an. Das Video hat keine Letterbox-Balken. Wenn beispielsweise ist das Poster-Art-Verhältnis ASPECT_RATIO_MOVIE_POSTER (1:1,441) aber das Videoverhältnis 16:9 beträgt, wechselt die Posteransicht zu einem 16:9-Bereich.
  • Vorschauen können öffentlich zugänglich oder öffentlich zugänglich sein. DRM-geschützt sind. Es gelten jeweils unterschiedliche Verfahren. Diese Seite beides beschreibt.

Vorschau auf dem Startbildschirm abspielen

Wenn Sie eine Vorschau mit einem der Videotypen erstellen unterstützt von ExoPlayer und die Vorschau öffentlich zugänglich ist, können Sie sie direkt auf dem Startbildschirm abspielen.

Wenn Sie ein PreviewProgram erstellen setPreviewVideoUri() mit einem öffentlich zugänglichen HTTPS-Protokoll verwenden URL wie im Beispiel unten dargestellt. Die Vorschau kann entweder Video oder 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));

Vorschau auf einer Oberfläche rendern

Falls Ihr Video DRM-geschützt ist oder in einem Medientyp vorliegt, der von ExoPlayer: Verwenden Sie TvInputService. Der Android TV-Startbildschirm übergibt eine Surface an deinen Dienst indem du onSetSurface() anrufst. Deine App lädt Videos von onTune() direkt auf diese Oberfläche.

Mit dem direkten Oberflächenrendering kann deine App bestimmen, was gerendert wird und wie es gerendert wird. gerendert. Du kannst Metadaten wie die Kanalattribution überlagern.

TvInputService im Manifest deklarieren

Deine App muss eine Implementierung von TvInputService bieten damit die Vorschau auf dem Startbildschirm gerendert werden kann.

Fügen Sie in Ihre Dienstdeklaration einen Intent-Filter ein, der Folgendes angibt: TvInputService als die auszuführende Aktion mit dem die Nutzerabsicht verstehen. Geben Sie außerdem die Dienstmetadaten als separate XML-Ressource an. Die Dienstdeklaration, Intent-Filter und Dienstmetadatendeklaration werden angezeigt im folgenden Beispiel:

<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 App und muss mit dem Namen der Ressource übereinstimmen, die Sie in der Manifests. Mit den Manifesteinträgen aus dem vorherigen Beispiel Erstellen Sie unter res/xml/previewinputservice.xml eine XML-Datei mit einer leeren tv-input-Tag:

<?xml version="1.0" encoding="utf-8"?>
<tv-input/>

Das TV Input Framework muss dieses Tag haben. Sie können jedoch werden nur zum Konfigurieren von Live-Kanälen verwendet. Da Sie ein Video rendern, sollte das Tag leer sein.

Video-URI erstellen

Um anzugeben, dass das Vorschauvideo von Ihrer App gerendert werden soll, anstatt Android TV-Startbildschirm müssen Sie einen Video-URI für eine PreviewProgram erstellen. Der URI sollte mit der ID enden, die Ihre App für die Inhalte verwendet, sodass Sie kann den Inhalt später im TvInputService abrufen.

Wenn die 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 mithilfe von 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();

Deine App ruft an onTune(Uri videoUri) damit Android TV das Vorschauvideo startet.

Dienst erstellen

Das folgende Beispiel zeigt, wie Sie TvInputService erweitern, um eine eigene zu erstellen. PreviewInputService. Beachte, dass der Dienst ein MediaPlayer für die Wiedergabe verwendet, Ihr Code kann 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
        }
    }
}