Önizleme videoları, kullanıcıları TV uygulamanıza derin bağlantı oluşturmaya teşvik etmek için harika bir yöntemdir. Önizlemeler, kısa kliplerden tam film fragmanlarına kadar değişebilir.
Önizleme oluştururken aşağıdaki yönergeleri göz önünde bulundurun:
- Önizlemede reklam göstermeyin. Reklamları istemci tarafında birleştiriyorsanız önizleme videolarına birleştirmeyin. Reklamları sunucu tarafında birleştiriyorsanız önizlemeler için reklamsız bir video sağlayın.
- En iyi kalite için önizleme videoları 16:9 veya 4:3 olmalıdır. Önizleme videolarının önerilen boyutları için Video programı özellikleri bölümüne bakın.
- Önizleme videosu ile poster resmi farklı en boy oranlarına sahip olduğunda, ana ekran önizlemeyi oynatmadan önce poster görünümünü videonun en boy oranına göre yeniden boyutlandırır. Video, sinemaskop biçiminde değil. Örneğin, poster resmi oranı
ASPECT_RATIO_MOVIE_POSTER(1:1, 441) ancak video oranı 16:9 ise poster görünümü 16:9 bölgesine dönüşür. - Oluşturduğunuz önizlemelerin içeriğine herkes erişebilir veya bu içerikler DRM ile korunabilir. Her durumda farklı prosedürler uygulanır. Bu sayfada her ikisi de açıklanmaktadır.
Ana ekranda önizlemeyi oynatma
ExoPlayer tarafından desteklenen video türlerinden herhangi birini kullanarak önizleme oluşturursanız ve önizlemeye herkese açık olarak erişilebiliyorsa önizlemeyi doğrudan ana ekranda oynatabilirsiniz.
PreviewProgram oluştururken aşağıdaki örnekte gösterildiği gibi herkese açık olarak erişilebilen bir HTTPS URL'siyle setPreviewVideoUri() kullanın. Önizleme video veya ses olabilir.
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));
Önizlemeyi bir yüzeyde oluşturma
Videonuz DRM ile korunuyorsa veya ExoPlayer tarafından desteklenmeyen bir medya türündeyse TvInputService kullanın. Android TV ana ekranı, onSetSurface() işlevini çağırarak hizmetinize Surface iletir. Uygulamanız, onTune() kaynağından doğrudan bu yüzeyde video çiziyor.
Doğrudan yüzey oluşturma, uygulamanızın neyin ve nasıl oluşturulacağını kontrol etmesini sağlar. Kanal ilişkilendirmesi gibi meta verileri yerleştirebilirsiniz.
TvInputService'inizi manifest dosyasında bildirin
Ana ekranın önizlemenizi oluşturabilmesi için uygulamanız TvInputService uygulamasını sağlamalıdır.
Hizmet beyanınızda, intent ile gerçekleştirilecek işlem olarak TvInputService'ı belirten bir intent filtresi ekleyin. Hizmet meta verilerini ayrı bir XML kaynağı olarak da tanımlayın. Hizmet beyanı, intent filtresi ve hizmet meta veri beyanı aşağıdaki örnekte gösterilmektedir:
<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>
Hizmet meta verilerini ayrı bir XML dosyasında tanımlayın.
Hizmet meta veri dosyası, uygulamanızın XML kaynakları dizininde bulunur ve manifest'te bildirdiğiniz kaynağın adıyla eşleşmelidir. Önceki örnekteki manifest girişlerini kullanarak res/xml/previewinputservice.xml konumunda boş bir tv-input etiketi içeren bir XML dosyası oluşturursunuz:
<?xml version="1.0" encoding="utf-8"?>
<tv-input/>
TV Input Framework'te bu etiket bulunmalıdır. Ancak bu özellik yalnızca canlı kanalları yapılandırmak için kullanılır. Video oluşturduğunuz için etiket boş olmalıdır.
Video URI'si oluşturma
Önizleme videonuzun Android TV ana ekranı yerine uygulamanız tarafından oluşturulması gerektiğini belirtmek için PreviewProgram için bir video URI'si oluşturmanız gerekir.
URI, uygulamanızın içerik için kullandığı tanımlayıcıyla bitmelidir. Böylece içeriği daha sonra TvInputService bölümünde alabilirsiniz.
Tanımlayıcınızın türü Long ise şu işlevi kullanın:
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();
Tanımlayıcınız Long türünde değilse URI'yi Uri.withAppendedPath() kullanarak oluşturun:
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();
Uygulamanız, Android TV'nin önizleme videosunu başlatması için
onTune(Uri videoUri)
çağrısı yapıyor.
Hizmet oluştur
Aşağıdaki örnekte, kendi PreviewInputService öğenizi oluşturmak için TvInputService öğesinin nasıl genişletileceği gösterilmektedir. Hizmetin oynatma için MediaPlayer kullandığını ancak kodunuzun mevcut herhangi bir video oynatıcıyı kullanabileceğini unutmayın.
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
}
}
}