प्रीव्यू वीडियो, लोगों को आपके टीवी ऐप्लिकेशन में डीप-लिंक करने के लिए बढ़ावा देने का एक शानदार तरीका है. प्रीव्यू, छोटी क्लिप से लेकर पूरी फ़िल्म के ट्रेलर तक हो सकते हैं.
झलक बनाते समय, इन दिशा-निर्देशों का पालन करें:
- झलक में विज्ञापन न दिखाएं. अगर क्लाइंट-साइड पर विज्ञापन स्टिच किए जाते हैं, तो उन्हें झलक वाले वीडियो में स्टिच न करें. अगर सर्वर साइड पर विज्ञापन स्टिच किए जाते हैं, तो झलक देखने के लिए बिना विज्ञापन वाला वीडियो उपलब्ध कराएं.
- सबसे अच्छी क्वालिटी के लिए, वीडियो की झलक 16:9 या 4:3 आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) में होनी चाहिए. प्रीव्यू वीडियो के सुझाए गए साइज़ के बारे में जानने के लिए, वीडियो प्रोग्राम के एट्रिब्यूट देखें.
- जब झलक वाले वीडियो और पोस्टर आर्ट का आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) अलग-अलग होता है, तो होम स्क्रीन पर झलक चलाने से पहले, पोस्टर व्यू का साइज़ बदलकर वीडियो के आसपेक्ट रेशियो के हिसाब से कर दिया जाता है. वीडियो लेटरबॉक्स नहीं किया गया है. उदाहरण के लिए, अगर पोस्टर आर्ट का रेशियो
ASPECT_RATIO_MOVIE_POSTER(1:1.441) है, लेकिन वीडियो का रेशियो 16:9 है, तो पोस्टर व्यू 16:9 के रेशियो में बदल जाएगा. - झलक बनाते समय, उसके कॉन्टेंट को सार्वजनिक तौर पर ऐक्सेस किया जा सकता है या उसे डीआरएम के तहत सुरक्षित किया जा सकता है. हर मामले में अलग-अलग प्रक्रियाएं लागू होती हैं. इस पेज पर, दोनों के बारे में बताया गया है.
होम स्क्रीन पर झलक चलाना
अगर आपने ExoPlayer के साथ काम करने वाले किसी वीडियो टाइप का इस्तेमाल करके झलक बनाई है और वह सार्वजनिक तौर पर उपलब्ध है, तो झलक को सीधे होम स्क्रीन पर चलाया जा सकता है.
PreviewProgram बनाते समय, setPreviewVideoUri() का इस्तेमाल करें. साथ ही, सार्वजनिक तौर पर ऐक्सेस किए जा सकने वाले एचटीटीपीएस यूआरएल का इस्तेमाल करें. उदाहरण के लिए, यहां दिया गया तरीका अपनाएं. झलक, वीडियो या ऑडियो में से किसी भी फ़ॉर्मैट में हो सकती है.
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));
किसी जगह पर झलक रेंडर करना
अगर आपका वीडियो, डीआरएम से सुरक्षित है या ऐसे मीडिया टाइप में है जिसे ExoPlayer सपोर्ट नहीं करता, तो TvInputService का इस्तेमाल करें. Android TV की होम स्क्रीन, onSetSurface() को कॉल करके आपकी सेवा को Surface पास करती है. आपका ऐप्लिकेशन, onTune() से सीधे इस प्लैटफ़ॉर्म पर वीडियो दिखाता है.
डायरेक्ट सर्फ़ेस रेंडरिंग की मदद से, आपका ऐप्लिकेशन यह कंट्रोल कर सकता है कि क्या रेंडर किया जाए और उसे कैसे रेंडर किया जाए. चैनल एट्रिब्यूशन जैसे मेटाडेटा को ओवरले किया जा सकता है.
मेनिफ़ेस्ट में TvInputService का एलान करना
आपके ऐप्लिकेशन में TvInputService को लागू किया जाना चाहिए, ताकि होम स्क्रीन पर आपकी झलक दिख सके.
अपनी सेवा के एलान में, एक ऐसा इंटेंट फ़िल्टर शामिल करें जो इंटेंट के साथ की जाने वाली कार्रवाई के तौर पर TvInputService को तय करता हो. इसके अलावा, सेवा के मेटाडेटा को एक अलग एक्सएमएल संसाधन के तौर पर भी घोषित करें. सेवा के एलान, इंटेंट फ़िल्टर, और सेवा के मेटाडेटा के एलान को यहां दिए गए उदाहरण में दिखाया गया है:
<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>
सेवा के मेटाडेटा को किसी अलग एक्सएमएल फ़ाइल में तय करें.
सेवा की मेटाडेटा फ़ाइल, आपके ऐप्लिकेशन के लिए XML संसाधन डायरेक्ट्री में मौजूद होती है. इसका नाम, मेनिफ़ेस्ट में बताए गए संसाधन के नाम से मेल खाना चाहिए. पिछले उदाहरण में दी गई मेनिफ़ेस्ट एंट्री का इस्तेमाल करके, आपको res/xml/previewinputservice.xml पर एक एक्सएमएल फ़ाइल बनानी होगी. इसमें tv-input टैग खाली होगा:
<?xml version="1.0" encoding="utf-8"?>
<tv-input/>
टीवी इनपुट फ़्रेमवर्क में यह टैग होना चाहिए. हालांकि, इसका इस्तेमाल सिर्फ़ लाइव चैनल कॉन्फ़िगर करने के लिए किया जाता है. वीडियो रेंडर किया जा रहा है, इसलिए टैग खाली होना चाहिए.
वीडियो का यूआरआई बनाना
अगर आपको यह बताना है कि Android TV की होम स्क्रीन के बजाय, आपका ऐप्लिकेशन झलक वाले वीडियो को रेंडर करे, तो आपको PreviewProgram के लिए वीडियो यूआरआई बनाना होगा.
यूआरआई, उस आइडेंटिफ़ायर पर खत्म होना चाहिए जिसका इस्तेमाल आपका ऐप्लिकेशन कॉन्टेंट के लिए करता है, ताकि बाद में TvInputService में कॉन्टेंट को वापस पाया जा सके.
अगर आपका आइडेंटिफ़ायर टाइप Long है, तो 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();
अगर आपका आइडेंटिफ़ायर, Long टाइप का नहीं है, तो 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();
आपका ऐप्लिकेशन, Android TV को झलक वाला वीडियो शुरू करने के लिए onTune(Uri videoUri) को कॉल करता है.
कोई सेवा बनाना
यहां दिए गए उदाहरण में, TvInputService को बढ़ाकर अपना PreviewInputService बनाने का तरीका बताया गया है. ध्यान दें कि यह सेवा, वीडियो चलाने के लिए MediaPlayer का इस्तेमाल करती है. हालांकि, आपका कोड किसी भी उपलब्ध वीडियो प्लेयर का इस्तेमाल कर सकता है.
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
}
}
}