প্রিভিউ ভিডিও

ব্যবহারকারীদের আপনার টিভি অ্যাপে প্রবেশ করতে উৎসাহিত করার জন্য প্রিভিউ ভিডিও একটি দারুণ উপায়। প্রিভিউগুলো ছোট ক্লিপ থেকে শুরু করে পুরো সিনেমার ট্রেলার পর্যন্ত হতে পারে।

প্রিভিউ তৈরি করার সময় এই নির্দেশিকাগুলো বিবেচনা করুন:

  • প্রিভিউতে বিজ্ঞাপন দেখাবেন না। যদি ক্লায়েন্ট সাইডে বিজ্ঞাপন যুক্ত করেন, তবে সেগুলো প্রিভিউ ভিডিওতে যুক্ত করবেন না। আর যদি সার্ভার সাইডে বিজ্ঞাপন যুক্ত করেন, তবে প্রিভিউয়ের জন্য একটি বিজ্ঞাপন-মুক্ত ভিডিও সরবরাহ করুন।
  • সর্বোত্তম মানের জন্য, প্রিভিউ ভিডিওর অনুপাত ১৬:৯ বা ৪:৩ হওয়া উচিত। প্রিভিউ ভিডিওর প্রস্তাবিত আকার জানতে ভিডিও প্রোগ্রাম অ্যাট্রিবিউটস দেখুন।
  • যখন প্রিভিউ ভিডিও এবং পোস্টার আর্টের অ্যাস্পেক্ট রেশিও ভিন্ন হয়, তখন হোম স্ক্রিন প্রিভিউটি প্লে করার আগে পোস্টার ভিউকে ভিডিওটির অ্যাস্পেক্ট রেশিও অনুযায়ী রিসাইজ করে। ভিডিওটি লেটারবক্সড হয় না। উদাহরণস্বরূপ, যদি পোস্টার আর্টের রেশিও ASPECT_RATIO_MOVIE_POSTER (১:১.৪৪১) হয় কিন্তু ভিডিওর রেশিও ১৬:৯ হয়, তাহলে পোস্টার ভিউটি একটি ১৬:৯ অঞ্চলে রূপান্তরিত হয়।
  • যখন আপনি একটি প্রিভিউ তৈরি করেন, তখন এর বিষয়বস্তু সর্বজনীনভাবে প্রবেশযোগ্য হতে পারে অথবা ডিআরএম (DRM) দ্বারা সুরক্ষিত থাকতে পারে। প্রতিটি ক্ষেত্রে ভিন্ন ভিন্ন পদ্ধতি প্রযোজ্য। এই পৃষ্ঠায় উভয় পদ্ধতিই বর্ণনা করা হয়েছে।

হোম স্ক্রিনে প্রিভিউটি চালান

আপনি যদি ExoPlayer দ্বারা সমর্থিত যেকোনো ভিডিও টাইপ ব্যবহার করে একটি প্রিভিউ তৈরি করেন এবং প্রিভিউটি সর্বজনীনভাবে অ্যাক্সেসযোগ্য হয়, তাহলে আপনি সরাসরি হোম স্ক্রিনে প্রিভিউটি প্লে করতে পারবেন।

যখন আপনি একটি প্রিভিউপ্রোগ্রাম তৈরি করবেন, তখন নিচের উদাহরণে দেখানো অনুযায়ী একটি সর্বজনীনভাবে অ্যাক্সেসযোগ্য HTTPS URL সহ setPreviewVideoUri() ব্যবহার করুন। প্রিভিউটি ভিডিও অথবা অডিও হতে পারে।

কোটলিন

val previewVideoUrl = Uri.parse("https://www.example.com/preview.mp4")
val builder = PreviewProgram.Builder()
builder.setChannelId(channelId)
    // ...
    .setPreviewVideoUri(previewVideoUrl)

জাভা

Uri previewVideoUrl = Uri.parse("https://www.example.com/preview.mp4");
PreviewProgram.Builder builder = new PreviewProgram.Builder();
builder.setChannelId(channelId)
    // ...
    .setPreviewVideoUri(Uri.parse(previewVideoUrl));

একটি পৃষ্ঠে প্রিভিউটি রেন্ডার করুন

আপনার ভিডিও যদি DRM-সুরক্ষিত হয় অথবা ExoPlayer দ্বারা সমর্থিত নয় এমন কোনো মিডিয়া টাইপের হয়, তাহলে একটি TvInputService ব্যবহার করুন। Android TV হোম স্ক্রিন onSetSurface() কল করার মাধ্যমে আপনার সার্ভিসে একটি Surface পাঠায়। আপনার অ্যাপ onTune() থেকে সরাসরি এই সারফেসের উপর ভিডিও আঁকে।

ডিরেক্ট সারফেস রেন্ডারিং আপনার অ্যাপকে নিয়ন্ত্রণ করতে দেয় যে কী এবং কীভাবে রেন্ডার করা হবে। আপনি চ্যানেল অ্যাট্রিবিউশনের মতো মেটাডেটা ওভারলে করতে পারেন।

ম্যানিফেস্টে আপনার TvInputService ঘোষণা করুন।

আপনার অ্যাপে অবশ্যই TvInputService এর একটি ইমপ্লিমেন্টেশন থাকতে হবে, যাতে হোম স্ক্রিন আপনার প্রিভিউটি রেন্ডার করতে পারে।

আপনার সার্ভিস ডিক্লারেশনে, একটি ইন্টেন্ট ফিল্টার অন্তর্ভুক্ত করুন যা ইন্টেন্টটির মাধ্যমে সম্পাদন করার জন্য অ্যাকশন হিসেবে TvInputService নির্দিষ্ট করে। এছাড়াও, সার্ভিস মেটাডেটাকে একটি পৃথক XML রিসোর্স হিসেবে ডিক্লেয়ার করুন। সার্ভিস ডিক্লারেশন, ইন্টেন্ট ফিল্টার এবং সার্ভিস মেটাডেটা ডিক্লারেশন নিম্নলিখিত উদাহরণে দেখানো হয়েছে:

<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 ফাইলে সার্ভিস মেটাডেটা সংজ্ঞায়িত করুন। সার্ভিস মেটাডেটা ফাইলটি আপনার অ্যাপের XML রিসোর্স ডিরেক্টরিতে অবস্থিত এবং ম্যানিফেস্টে ঘোষিত রিসোর্সের নামের সাথে অবশ্যই মিলতে হবে। পূর্ববর্তী উদাহরণের ম্যানিফেস্ট এন্ট্রিগুলো ব্যবহার করে, আপনি res/xml/previewinputservice.xml এ একটি XML ফাইল তৈরি করবেন, যেখানে একটি খালি tv-input ট্যাগ থাকবে:

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

টিভি ইনপুট ফ্রেমওয়ার্কে এই ট্যাগটি অবশ্যই থাকতে হবে। তবে, এটি শুধুমাত্র লাইভ চ্যানেল কনফিগার করার জন্য ব্যবহৃত হয়। যেহেতু আপনি একটি ভিডিও রেন্ডার করছেন, তাই ট্যাগটি খালি থাকা উচিত।

একটি ভিডিও ইউআরআই তৈরি করুন

আপনার প্রিভিউ ভিডিওটি অ্যান্ড্রয়েড টিভি হোম স্ক্রিনের পরিবর্তে আপনার অ্যাপ দ্বারা রেন্ডার করা হবে, এটি নির্দেশ করার জন্য আপনাকে একটি PreviewProgram জন্য একটি ভিডিও URI তৈরি করতে হবে। URI-টির শেষে অবশ্যই সেই আইডেন্টিফায়ারটি থাকতে হবে যা আপনার অ্যাপ কন্টেন্টের জন্য ব্যবহার করে, যাতে আপনি পরবর্তীতে TvInputService এ কন্টেন্টটি পুনরুদ্ধার করতে পারেন।

আপনার আইডেন্টিফায়ার Long টাইপের হলে, TvContractCompat.buildPreviewProgramUri() ব্যবহার করুন:

কোটলিন

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()

জাভা

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() ব্যবহার করে URI তৈরি করুন:

কোটলিন

val previewProgramVideoUri = Uri.withAppendedPath(PreviewPrograms.CONTENT_URI, "content-identifier")
       .buildUpon()
       .appendQueryParameter("input", TvContractCompat.buildInputId(componentName))
       .build()

জাভা

previewProgramVideoUri = Uri.withAppendedPath(PreviewPrograms.CONTENT_URI, "content-identifier")
       .buildUpon()
       .appendQueryParameter("input", TvContractCompat.buildInputId(componentName))
       .build();

আপনার অ্যাপ অ্যান্ড্রয়েড টিভিকে প্রিভিউ ভিডিও চালু করার জন্য onTune(Uri videoUri) কল করে।

একটি পরিষেবা তৈরি করুন

নিম্নলিখিত উদাহরণটি দেখায় কিভাবে TvInputService প্রসারিত করে আপনার নিজস্ব PreviewInputService তৈরি করা যায়। উল্লেখ্য যে, এই সার্ভিসটি প্লেব্যাকের জন্য একটি MediaPlayer ব্যবহার করে, কিন্তু আপনার কোড যেকোনো উপলব্ধ ভিডিও প্লেয়ার ব্যবহার করতে পারে।

কোটলিন

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"
    }
}

জাভা

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
        }
    }
}