পণ্যের খবর

মিডিয়া প্লেব্যাকের মান উন্নয়ন: মিডিয়া৩-এর সাথে প্রি-লোডিংয়ের পরিচিতি - পর্ব ১

৮ মিনিটের পাঠ
Mayuri Khinvasara Khabya
ডেভেলপার সম্পর্ক প্রকৌশলী

আজকের মিডিয়া-কেন্দ্রিক অ্যাপগুলোতে, একটি মসৃণ ও নিরবচ্ছিন্ন প্লেব্যাক অভিজ্ঞতা প্রদান করাই হলো ব্যবহারকারীর জন্য আনন্দদায়ক অভিজ্ঞতার মূল চাবিকাঠি। ব্যবহারকারীরা আশা করেন যে তাদের ভিডিওগুলো সঙ্গে সঙ্গে শুরু হবে এবং কোনো বিরতি ছাড়াই নির্বিঘ্নে চলতে থাকবে।

মূল চ্যালেঞ্জটি হলো ল্যাটেন্সি। প্রচলিতভাবে, ব্যবহারকারী প্লেব্যাকের জন্য কোনো একটি আইটেম বেছে নেওয়ার পরেই একটি ভিডিও প্লেয়ার তার কাজ—যেমন সংযোগ স্থাপন, ডাউনলোড, পার্সিং এবং বাফারিং—শুরু করে। আজকের শর্ট-ফর্ম ভিডিওর প্রেক্ষাপটে এই প্রতিক্রিয়াশীল পদ্ধতিটি ধীরগতির। এর সমাধান হলো সক্রিয় হওয়া। ব্যবহারকারী এরপর কী দেখবেন তা আমাদের আগে থেকেই অনুমান করতে হবে এবং সেই অনুযায়ী কনটেন্ট প্রস্তুত রাখতে হবে। এটাই হলো প্রি-লোডিংয়ের মূল কথা।

প্রিলোডিংয়ের প্রধান সুবিধাগুলো হলো:

  • 🚀 দ্রুততর প্লেব্যাক শুরু: ভিডিওগুলো আগে থেকেই প্রস্তুত থাকে, ফলে বিভিন্ন অংশের মধ্যে দ্রুত পরিবর্তন হয় এবং ভিডিওটি আরও দ্রুত শুরু করা যায়।
  • 📉 বাফারিং হ্রাস: আগে থেকেই ডেটা লোড করার ফলে, প্লেব্যাক আটকে যাওয়ার সম্ভাবনা অনেক কমে যায়, যেমন নেটওয়ার্কের সমস্যার কারণে।
  • ✨ ফলস্বরূপ আরও মসৃণ ব্যবহারকারীর অভিজ্ঞতা: দ্রুত শুরু হওয়া এবং কম বাফারিংয়ের সমন্বয়ে ব্যবহারকারীরা আরও সাবলীল ও নির্বিঘ্ন ইন্টারঅ্যাকশন উপভোগ করতে পারেন।

এই তিন পর্বের সিরিজে, আমরা কম্পোনেন্ট (প্রি)লোড করার জন্য Media3-এর শক্তিশালী ইউটিলিটিগুলোর সাথে পরিচয় করিয়ে দেব এবং সেগুলোর গভীরে আলোচনা করব।

  • প্রথম অংশে, আমরা মূল বিষয়গুলো নিয়ে আলোচনা করব: Media3-তে উপলব্ধ বিভিন্ন প্রিলোডিং কৌশল বোঝা, PreloadConfiguration সক্রিয় করা এবং DefaultPreloadManager সেট আপ করা, এবং আপনার অ্যাপকে আইটেম প্রিলোড করার জন্য সক্ষম করা। এই ব্লগটির শেষে, আপনি আপনার কনফিগার করা র‍্যাঙ্কিং এবং সময়কাল অনুযায়ী মিডিয়া আইটেম প্রিলোড ও প্লে করতে সক্ষম হবেন।
  • দ্বিতীয় পর্বে , আমরা DefaultPreloadManager-এর আরও উন্নত বিষয় নিয়ে আলোচনা করব: অ্যানালিটিক্সের জন্য লিসেনার ব্যবহার, স্লাইডিং উইন্ডো প্যাটার্নের মতো প্রোডাকশন-উপযোগী সেরা অনুশীলনগুলো অন্বেষণ এবং DefaultPreloadManager ও ExoPlayer-এর কাস্টম শেয়ার্ড কম্পোনেন্ট।
  • তৃতীয় পর্বে, আমরা DefaultPreloadManager ব্যবহার করে ডিস্ক ক্যাশিং সম্পর্কে বিস্তারিত আলোচনা করব।

প্রি-লোডিংই ভরসা! 🦸‍♀️

প্রি-লোডিংয়ের মূল ধারণাটি খুবই সহজ: আপনার প্রয়োজন হওয়ার আগেই মিডিয়া কনটেন্ট লোড করে নেওয়া। একজন ব্যবহারকারী যখন পরবর্তী ভিডিওতে যাওয়ার জন্য সোয়াইপ করেন, ততক্ষণে ভিডিওটির প্রথম অংশগুলো ডাউনলোড হয়ে যায় এবং তাৎক্ষণিক প্লেব্যাকের জন্য প্রস্তুত থাকে।

বিষয়টাকে একটা রেস্তোরাঁর মতো করে ভাবুন। একটি ব্যস্ত রান্নাঘর অর্ডার পাওয়ার জন্য অপেক্ষা না করেই পেঁয়াজ কাটা শুরু করে। 🧅 তারা তাদের প্রস্তুতির কাজ আগে থেকেই করে রাখে। প্রি-লোডিং হলো আপনার ভিডিও প্লেয়ারের জন্য সেই প্রস্তুতির কাজ।

সক্রিয় করা থাকলে, প্লেব্যাক বাফার পরবর্তী আইটেমে পৌঁছানোর আগেই ব্যবহারকারী যখন পরের আইটেমে চলে যান, তখন প্রি-লোডিং জয়েন ল্যাটেন্সি কমাতে সাহায্য করতে পারে। পরবর্তী উইন্ডোর প্রথম পর্ব প্রস্তুত করা হয় এবং ভিডিও, অডিও ও টেক্সট স্যাম্পল বাফার করা হয়। প্রি-লোড করা পর্বটি পরে প্লেয়ারে কিউ করা হয়, যেখানে বাফার করা স্যাম্পলগুলো তাৎক্ষণিকভাবে উপলব্ধ থাকে এবং রেন্ডারিংয়ের জন্য কোডেকে পাঠানোর জন্য প্রস্তুত থাকে।

Media3-তে প্রি-লোডিংয়ের জন্য দুটি প্রধান API রয়েছে, যেগুলোর প্রতিটি ভিন্ন ভিন্ন ব্যবহারের জন্য উপযুক্ত। সঠিক API নির্বাচন করাই হলো প্রথম ধাপ।

১. PreloadConfiguration ব্যবহার করে প্লেলিস্ট আইটেম প্রি-লোড করা

এটি একটি সহজ পদ্ধতি, যা প্লেলিস্টের মতো রৈখিক ও ক্রমিক মিডিয়ার জন্য উপযোগী, যেখানে প্লেব্যাকের ক্রম অনুমানযোগ্য (যেমন একাধিক পর্বের একটি সিরিজ)। আপনি ExoPlayer-এর প্লেলিস্ট API ব্যবহার করে প্লেয়ারকে মিডিয়া আইটেমগুলোর সম্পূর্ণ তালিকা দেন এবং প্লেয়ারের জন্য PreloadConfiguration সেট করেন, এরপর এটি কনফিগার করা অনুযায়ী ক্রমানুসারে পরবর্তী আইটেমগুলো স্বয়ংক্রিয়ভাবে প্রি-লোড করে নেয়। যখন প্লেব্যাক বাফার পরবর্তী আইটেমে ওভারল্যাপ করার আগেই কোনো ব্যবহারকারী পরের আইটেমে চলে যান, তখন এই API-টি জয়েন ল্যাটেন্সি অপ্টিমাইজ করার চেষ্টা করে।

চলমান প্লেব্যাকের জন্য যখন কোনো মিডিয়া লোড করা হচ্ছে না, শুধুমাত্র তখনই প্রি-লোডিং শুরু হয়, যা এটিকে মূল প্লেব্যাকের সাথে ব্যান্ডউইথের জন্য প্রতিযোগিতা করা থেকে বিরত রাখে।

আপনার প্রিলোডিং প্রয়োজন কিনা, সে বিষয়ে যদি আপনি এখনও নিশ্চিত না হন, তবে এটি পরীক্ষা করে দেখার জন্য এই এপিআইটি একটি দারুণ ও সহজ উপায়!

player.preloadConfiguration =
    PreloadConfiguration(/* targetPreloadDurationUs= */ 5_000_000L)

উপরের PreloadConfiguration- এর মাধ্যমে, প্লেয়ারটি প্লেলিস্টের পরবর্তী আইটেমের জন্য পাঁচ সেকেন্ডের মিডিয়া প্রি-লোড করার চেষ্টা করে।

একবার অপ্ট-ইন করার পর, PreloadConfiguration.DEFAULT ব্যবহার করে প্লেলিস্ট প্রি-লোডিং আবার বন্ধ করা যেতে পারে।

player.preloadConfiguration = PreloadConfiguration.DEFAULT

২. PreloadManager ব্যবহার করে ডাইনামিক লিস্ট প্রি-লোড করা

ভার্টিকাল ফিড বা ক্যারোসেলের মতো ডাইনামিক UI-এর জন্য, যেখানে ব্যবহারকারীর ইন্টারঅ্যাকশনের মাধ্যমে 'পরবর্তী' আইটেমটি নির্ধারিত হয়, PreloadManager API উপযুক্ত। এটি Media3 ExoPlayer লাইব্রেরির মধ্যে একটি নতুন শক্তিশালী, স্বতন্ত্র কম্পোনেন্ট যা বিশেষভাবে প্রোঅ্যাকটিভভাবে প্রিলোড করার জন্য ডিজাইন করা হয়েছে। এটি সম্ভাব্য MediaSource-এর একটি সংগ্রহ পরিচালনা করে, ব্যবহারকারীর বর্তমান অবস্থানের নৈকট্যের উপর ভিত্তি করে সেগুলোকে অগ্রাধিকার দেয় এবং কী প্রিলোড করতে হবে তার উপর সূক্ষ্ম নিয়ন্ত্রণ প্রদান করে, যা শর্ট-ফর্ম ভিডিওর ডাইনামিক ফিডের মতো জটিল পরিস্থিতির জন্য উপযুক্ত।

আপনার প্রিলোডম্যানেজার সেট আপ করা

DefaultPreloadManager হলো PreloadManager-এর আদর্শ বাস্তবায়ন।

DefaultPreloadManager এর বিল্ডার DefaultPreloadManager এবং এর প্রি-লোড করা কন্টেন্ট প্লে করার জন্য যেকোনো ExoPlayer ইনস্ট্যান্স, উভয়ই তৈরি করতে পারে। একটি DefaultPreloadManager তৈরি করতে, আপনাকে একটি TargetPreloadStatusControl পাস করতে হবে, যেখান থেকে প্রি-লোড ম্যানেজার কোনো আইটেমের জন্য কী পরিমাণ লোড করতে হবে তা জানতে কোয়েরি করতে পারে। আমরা নিচের অংশে TargetPreloadStatusControl-এর একটি উদাহরণ ব্যাখ্যা ও সংজ্ঞায়িত করব।

val preloadManagerBuilder =
DefaultPreloadManager.Builder(context, targetPreloadStatusControl)
val preloadManager = val preloadManagerBuilder.build()

// Build ExoPlayer with DefaultPreloadManager.Builder
val player = preloadManagerBuilder.buildExoPlayer()

ExoPlayer এবং DefaultPreloadManager উভয়ের জন্য একই বিল্ডার ব্যবহার করা আবশ্যক, যা নিশ্চিত করে যে এদের অভ্যন্তরীণ কম্পোনেন্টগুলো সঠিকভাবে শেয়ার করা হচ্ছে।

ব্যাস! এখন আপনার কাছে নির্দেশনা গ্রহণের জন্য একজন ম্যানেজার প্রস্তুত আছে।

TargetPreloadStatusControl ব্যবহার করে সময়কাল এবং র‍্যাঙ্কিং কনফিগার করা

ধরুন, আপনি ১০ সেকেন্ডের ভিডিও আগে থেকে লোড করতে চান। আপনি ক্যারোসেলে আপনার মিডিয়া আইটেমগুলোর অবস্থান নির্দিষ্ট করে দিতে পারেন, এবং DefaultPreloadManager ব্যবহারকারী বর্তমানে যে আইটেমটি চালাচ্ছেন তার থেকে আইটেমটির দূরত্বের উপর ভিত্তি করে লোড করার ক্ষেত্রে অগ্রাধিকার দেয়।

আইটেমটি কতক্ষণ প্রি-লোড হবে তা যদি আপনি নিয়ন্ত্রণ করতে চান, তাহলে DefaultPreloadManager.PreloadStatus রিটার্ন করার মাধ্যমে তা নির্ধারণ করতে পারেন।

উদাহরণস্বরূপ,

  • আইটেম 'এ' সর্বোচ্চ অগ্রাধিকারের, ৫ সেকেন্ডের ভিডিও লোড করুন।
  • আইটেম 'বি'-এর অগ্রাধিকার মাঝারি, কিন্তু যখন আপনি সেখানে পৌঁছাবেন, তখন ৩ সেকেন্ডের ভিডিও লোড করুন।
  • আইটেম 'C'-এর অগ্রাধিকার কম, শুধু ট্র্যাকগুলো লোড করুন।
  • আইটেম 'ডি'-এর গুরুত্ব আরও কম, শুধু প্রস্তুতি নিন।
  • অন্যান্য আইটেমগুলো অনেক দূরে আছে, আগে থেকে কিছু লোড করবেন না।

এই সূক্ষ্ম নিয়ন্ত্রণ আপনাকে আপনার রিসোর্স ব্যবহার অপ্টিমাইজ করতে সাহায্য করতে পারে, যা একটি নির্বিঘ্ন প্লেব্যাকের জন্য বাঞ্ছনীয়।

import androidx.media3.exoplayer.DefaultPreloadManager.PreloadStatus


class MyTargetPreloadStatusControl(
    currentPlayingIndex: Int = C.INDEX_UNSET
) : TargetPreloadStatusControl<Int,PreloadStatus> {


    // The app is responsible for updating this based on UI state
    override fun getTargetPreloadStatus(index: Int): PreloadStatus? {

        val distance = index - currentPlayingIndex

        // Adjacent items (Next): preload 5 seconds
        if (distance == 1) { 
        // Return a PreloadStatus that is labelled by STAGE_SPECIFIED_RANGE_LOADED and suggest loading // 5000ms from the default start position
                    return PreloadStatus.specifiedRangeLoaded(5000L)
                } 

        // Adjacent items (Previous): preload 3 seconds
        else if (distance == -1) { 
        // Return a PreloadStatus that is labelled by STAGE_SPECIFIED_RANGE_LOADED //and suggest loading 3000ms from the default start position
                    return PreloadStatus.specifiedRangeLoaded(3000L)
                } 

        // Items two positions away: just select tracks
        else if (distance) == 2) {
        // Return a PreloadStatus that is labelled by STAGE_TRACKS_SELECTED
                    return PreloadStatus.TRACKS_SELECTED
                } 

        // Items four positions away: just select prepare
        else if (abs(distance) <= 4) {
        // Return a PreloadStatus that is labelled by STAGE_SOURCE_PREPARED
                    return PreloadStatus.SOURCE_PREPARED
                }

             // All other items are too far away
             return null
            }
}

পরামর্শ: PreloadManager আগের এবং পরের উভয় আইটেমই আগে থেকে লোড করে রাখতে পারে, অন্যদিকে PreloadConfiguration শুধুমাত্র পরবর্তী আইটেমগুলোই দেখবে।

প্রি-লোডিং আইটেমগুলি পরিচালনা করা

আপনার ম্যানেজার তৈরি হয়ে গেলে, আপনি তাকে কী কাজ করতে হবে তা বলে দিতে পারেন। আপনার ব্যবহারকারী যখন ফিড স্ক্রল করবে, আপনি আসন্ন ভিডিওগুলো শনাক্ত করে সেগুলোকে ম্যানেজারে যুক্ত করবেন। প্রি-লোড ম্যানেজারের সাথে মিথস্ক্রিয়াটি হলো আপনার UI এবং প্রি-লোডিং ইঞ্জিনের মধ্যে একটি অবস্থা-চালিত কথোপকথন।

১. মিডিয়া আইটেম যোগ করুন

আপনি যখন আপনার ফিডটি পূরণ করবেন, তখন ম্যানেজারকে অবশ্যই জানাতে হবে যে এটি কোন মিডিয়া ট্র্যাক করবে। আপনি যদি নতুন শুরু করেন, তাহলে আপনি যে সম্পূর্ণ তালিকাটি প্রি-লোড করতে চান তা যোগ করতে পারেন। পরবর্তীতে, প্রয়োজন অনুযায়ী আপনি তালিকায় একটি করে আইটেম যোগ করতে পারেন। প্রি-লোডিং তালিকায় কোন আইটেমগুলো থাকবে তার উপর আপনার সম্পূর্ণ নিয়ন্ত্রণ রয়েছে, যার অর্থ হলো ম্যানেজার থেকে কী যোগ করা হচ্ছে এবং সরানো হচ্ছে তাও আপনাকে পরিচালনা করতে হবে।

val initialMediaItems = pullMediaItemsFromService(/* count= */ 20)
for (index in 0 until initialMediaItems.size) {
    preloadManager.add(
        initialMediaItems.get(index),index)
    )
}

ম্যানেজার এখন ব্যাকগ্রাউন্ডে এই MediaItem টির জন্য ডেটা সংগ্রহ করা শুরু করবে।

যোগ করার পরে, ম্যানেজারকে তার নতুন তালিকাটি পুনরায় মূল্যায়ন করতে বলুন (এই ইঙ্গিত দিয়ে যে কিছু পরিবর্তন হয়েছে, যেমন কোনো আইটেম যোগ করা বা সরানো, অথবা ব্যবহারকারী একটি নতুন আইটেম খেলতে যাচ্ছে)।

preloadManager.invalidate()

২. একটি আইটেম পুনরুদ্ধার করুন এবং চালান

এবার আসছে মূল প্লেব্যাক লজিক। যখন ব্যবহারকারী সেই ভিডিওটি প্লে করার সিদ্ধান্ত নেন, তখন আপনার একটি নতুন MediaSource তৈরি করার প্রয়োজন নেই। এর পরিবর্তে, আপনি PreloadManager এর কাছে তার আগে থেকে প্রস্তুত করা MediaSource-টি চেয়ে নেবেন। আপনি MediaItem ব্যবহার করে Preload Manager থেকে MediaSource-টি পেতে পারেন।

PreloadManager থেকে প্রাপ্ত আইটেমটি যদি null হয়, তার মানে হলো mediaItem-টি এখনও প্রি-লোড করা হয়নি বা PreloadManager-এ যোগ করা হয়নি, তাই আপনি সরাসরি mediaItem-টি সেট করতে পারেন।

// When a media item is about to displ​​ay on the screen
val mediaSource = preloadManager.getMediaSource(mediaItem)
if (mediaSource!= null) {
  player.setMediaSource(mediaSource)
} else {
  // If mediaSource is null, that mediaItem hasn't been added yet.
  // So, send it directly to the player.
  player.setMediaItem(mediaItem)
}
player.prepare()
// When the media item is displaying at the center of the screen
player.play()

PreloadManager থেকে প্রাপ্ত MediaSource প্রস্তুত করার মাধ্যমে, আপনি মেমরিতে আগে থেকেই থাকা ডেটা ব্যবহার করে প্রি-লোডিং থেকে প্লেব্যাকে নির্বিঘ্নে স্থানান্তরিত হতে পারেন। এ কারণেই শুরুর সময় দ্রুততর হয়।

৩. বর্তমান সূচককে UI-এর সাথে সিঙ্ক্রোনাইজ করে রাখুন

যেহেতু আমাদের ফিড/তালিকা পরিবর্তনশীল হতে পারে, তাই আপনার বর্তমান প্লেয়িং ইনডেক্স সম্পর্কে PreloadManager-কে জানানো গুরুত্বপূর্ণ, যাতে এটি প্রি-লোডিংয়ের জন্য সর্বদা আপনার বর্তমান ইনডেক্সের নিকটতম আইটেমগুলোকে অগ্রাধিকার দিতে পারে।

preloadManager.setCurrentPlayingIndex(currentIndex)
// Need to call invalidate() to update the priorities
preloadManager.invalidate()

৪. একটি আইটেম সরান

ম্যানেজারকে কার্যকর রাখতে, ব্যবহারকারীর বর্তমান অবস্থান থেকে দূরে থাকা আইটেমের মতো যেসব আইটেম ট্র্যাক করার আর প্রয়োজন নেই, সেগুলো সরিয়ে ফেলা উচিত।

// When an item is too far from the current playing index
preloadManager.remove(mediaItem)

একবারে সমস্ত আইটেম মুছে ফেলার প্রয়োজন হলে, আপনি preloadManager.reset() কল করতে পারেন।

৫. ম্যানেজারকে অব্যাহতি দিন

যখন আপনার PreloadManager-এর আর প্রয়োজন হবে না (যেমন, যখন আপনার UI ধ্বংস হয়ে যায়), তখন এর রিসোর্সগুলো মুক্ত করার জন্য আপনাকে অবশ্যই এটি রিলিজ করতে হবে। এটি করার জন্য একটি ভালো জায়গা হলো যেখানে আপনি ইতিমধ্যেই আপনার প্লেয়ারের রিসোর্সগুলো রিলিজ করছেন। প্লেয়ারের আগে ম্যানেজারটি রিলিজ করার পরামর্শ দেওয়া হয়, কারণ আপনার আর কোনো প্রিলোডিংয়ের প্রয়োজন না হলে প্লেয়ারটি খেলা চালিয়ে যেতে পারে।

// In your Activity's onDestroy() or Composable's onDispose
preloadManager.release()

ডেমো সময়

সরাসরি দেখুন 👍

নীচের ডেমোতে, আমরা ডানদিকে PreloadManager-এর প্রভাব দেখতে পাচ্ছি, যার ফলে ভিডিও দ্রুত লোড হয়, অন্যদিকে বামদিকে বিদ্যমান অভিজ্ঞতা দেখানো হয়েছে। আপনি ডেমোটির জন্য কোড স্যাম্পলটিও দেখতে পারেন। (বোনাস: এটি প্রতিটি ভিডিওর স্টার্টআপ ল্যাটেন্সিও প্রদর্শন করে)

ডেমো-প্রিলোডম্যানেজার_২.ওয়েবপি

এরপর কী?

এবং এখানেই প্রথম পর্ব শেষ! একটি ডাইনামিক প্রিলোডিং সিস্টেম তৈরি করার জন্য প্রয়োজনীয় টুলস এখন আপনার কাছে রয়েছে। আপনি হয় ExoPlayer-এ একটি প্লেলিস্টের পরবর্তী আইটেম প্রিলোড করতে PreloadConfiguration ব্যবহার করতে পারেন, অথবা একটি DefaultPreloadManager সেট আপ করে তাৎক্ষণিকভাবে আইটেম যোগ ও অপসারণ করতে, টার্গেট প্রিলোড স্ট্যাটাস কনফিগার করতে এবং প্লেব্যাকের জন্য প্রিলোড করা কন্টেন্ট সঠিকভাবে পুনরুদ্ধার করতে পারেন।

দ্বিতীয় পর্বে , আমরা DefaultPreloadManager নিয়ে আরও বিস্তারিত আলোচনা করব। আমরা দেখব কীভাবে প্রি-লোডিং ইভেন্ট শোনা যায়, মেমরি সমস্যা এড়াতে স্লাইডিং উইন্ডো ব্যবহারের মতো সেরা পদ্ধতিগুলো নিয়ে আলোচনা করব, এবং ExoPlayer ও DefaultPreloadManager-এর কাস্টম শেয়ার্ড কম্পোনেন্টগুলোর অভ্যন্তরীণ কার্যপ্রণালী দেখব।

আপনার কি কোনো মতামত জানানোর আছে? আমরা আপনার কথা শোনার জন্য আগ্রহী।

সাথে থাকুন, আর আপনার অ্যাপটিকে আরও দ্রুত করে তুলুন! 🚀

    লিখেছেন:

    পড়তে থাকুন