ব্যবহারকারীরা মোবাইল ডিভাইসে যে সময় কাটান তার বেশিরভাগটাই মিডিয়া কনজিউম করার জন্য ব্যয় হয়, যার জন্য প্লেব্যাক অভিজ্ঞতা ত্রুটিহীন, অত্যন্ত দক্ষ এবং ব্যাটারির আয়ুর কথা মাথায় রেখে তৈরি করা প্রয়োজন। এছাড়াও, ব্যবহারকারীরা আশা করেন যে এই অভিজ্ঞতাগুলি তাদের ডিভাইস জুড়ে নির্বিঘ্নে ট্রানজিশন করবে, ফোন থেকে শুরু করে বসার ঘরের টিভি এবং আরও অনেক কিছু।
Media3 ও ExoPlayer-এ আর্কিটেকচারাল আপডেট কীভাবে বিভিন্ন ফর্ম ফ্যাক্টর জুড়ে সিমলেস প্লেব্যাককে শক্তিশালী করে তা এক্সপ্লোর করুন। এই আলোচনায় Media3 Compose UI টুলকিটের মাধ্যমে রেসপন্সিভ ইন্টারফেস তৈরি করা, নতুন PreloadManager ব্যবহার করে ফিডে বাফারিংয়ের সমস্যা দূর করা এবং CastPlayer ও স্পেশিয়াল অডিওর মাধ্যমে আপনার অ্যাপকে বসার ঘরের স্ক্রিন ও Android XR-এ নিয়ে যাওয়ার বিষয়ে আলোচনা করা হবে।
ট্রান্সস্ক্রিপ্ট করা
ঠিক আছে।
সবাইকে স্বাগত।
আমার নাম টনি।
আমি Android মিডিয়া টিমের একজন ইঞ্জিনিয়ার।
এবং ক্রিস্টিনা ও ডোনোভানের সাথে আমরা আলোচনা করব যে Android-এ আপনার সব মিডিয়া সংক্রান্ত প্রয়োজনীয়তা Jetpack Media3 কীভাবে পূরণ করতে পারে।
Media3 হল Android-এর সাপোর্ট লাইব্রেরি যা মিডিয়া সম্পর্কিত সবকিছুর জন্য ব্যবহার করা হয়, যেমন ExoPlayer-এর মাধ্যমে প্লেব্যাক, মিডিয়া সেশন ও Cast-এর মাধ্যমে মিডিয়া শেয়ার করা, ট্রান্সফর্মারের মাধ্যমে মিডিয়া এডিট করা অথবা ফ্রেম বা মেটাডেটা এক্সট্র্যাক্ট করার মতো মিডিয়া পরীক্ষা করা।
Media3 একটি লাইব্রেরি গ্রুপে এই সম্পূর্ণ স্পেস কভার করে।
সহায়ক লাইব্রেরি হিসেবে, এটি আপনার অ্যাপে বান্ডেল করা থাকে।
এর অর্থ হল, আমরা ধারাবাহিকতা নিশ্চিত করতে পারি, যাতে একই কোড সব OS ভার্সন ও সব ডিভাইসে রান করে।
এটি আপডেট করার ক্ষেত্রেও সাহায্য করে।
আমরা যে সমস্ত ত্রুটি সমাধান করি তা API 24 পর্যন্ত পৌঁছায় এবং এটি কোনও OS রিলিজ চক্রের সাথে যুক্ত নয়।
এবং একটি সাপোর্ট লাইব্রেরি হিসেবে, আমরা খুব সমৃদ্ধ কাস্টমাইজেশন বিকল্পের অনুমতি দিতে পারি, যা Android ফ্রেমওয়ার্কে সম্ভব হবে না।
GitHub-এ লাইব্রেরি হিসেবে, আমরা প্রথমে ওপেন-সোর্স।
এর অর্থ হল, আমাদের করা প্রতিটি পরিবর্তন GitHub-এ অবিলম্বে উপলভ্য হয়।
আমাদের একটি অ্যাক্টিভ ইস্যু ট্র্যাকার আছে এবং আমরা পুল রিকোয়েস্ট গ্রহণ করছি।
এইসব ব্যবহারের ক্ষেত্রে, হাইলাইট করার মতো মূল বিষয় হল, আমরা সব লেভেলের বিবরণের ব্যাপারে যত্নশীল, হাই-লেভেল UI এলিমেন্ট থেকে শুরু করে সহজ আউট-অফ-দ্য-বক্স API, তবে গভীর কাস্টমাইজেশন বিকল্প, বিভিন্ন ফর্ম্যাট ও স্ট্যান্ডার্ডের জন্য ব্যাপক সহায়তা এবং পারফর্ম্যান্স ও দক্ষতার ভিত্তি, এই সবকিছুর ব্যাপারে আমরা যত্নশীল।
Media3 এই সম্পূর্ণ স্পেস কভার করে।
আজ, আমরা এই ধরনের কিছু বিষয় আরও গভীরভাবে জানার চেষ্টা করছি।
আমরা আমাদের নতুন Compose UI মডিউল, নতুন CastPlayer যা মিডিয়া সেশনের সাথে শেয়ার করা আরও সহজ করে তোলে, নতুন উন্নত এফেক্ট সহ একটি নতুন এডিটিং পাইপলাইন, মেটাডেটা ও ফ্রেম ফিরিয়ে আনার জন্য নতুন টুল, কিছু নতুন স্ট্রিমিং প্রযুক্তি, বিশেষ করে, Eclipsa ভিডিও ও অডিও এবং প্রিলোডিং, স্ক্রাবিং ও ব্যাটারি সঞ্চয়ের জন্য বেশ কিছু কোয়ালিটি অফ এক্সপেরিয়েন্স ইউটিলিটি সম্পর্কে কথা বলতে চলেছি।
এখন, প্রথম টপিকটি সরাসরি দেখা যাক, Media3 কীভাবে মিডিয়ার জন্য UI এলিমেন্ট তৈরি করতে সাহায্য করতে পারে।
আমরা সম্প্রতি দুটি নতুন মডিউল প্রকাশ করেছি: Media3 UI Compose এবং Media3 UI Compose Material 3।
এখানে, আপনি একটি হাই-লেভেল প্লেয়ার কম্পোজেবল দেখতে পারেন, কারণ এটি Media3 1.10-এ লঞ্চ করা হয়েছিল এবং এতে আর কোনও পরিবর্তন করা হয়নি।
@Composable
fun videoScreen() {
Player(viewModel.exoPlayer)
}এটি খুব সহজেই কাজ করে।
এটির জন্য শুধু Media3 প্লেয়ার প্রয়োজন।
এখানে যে উদাহরণ দেওয়া হয়েছে, সেটি হল ExoPlayer, যা সাধারণত আপনার ভিউ মডেলে থাকে।
তবে এটি অন্য কিছুও হতে পারে, যেমন CastPlayer, মিডিয়া কন্ট্রোলার বা আপনার অ্যাপে থাকা অন্য কোনও প্লেয়ার।
এখানে ExoPlayer-এর ভূমিকা যে সবচেয়ে গুরুত্বপূর্ণ তা উল্লেখ করা প্রয়োজন।
এতে সব তথ্য থাকে এবং প্লেয়ার কম্পোজেবল UI রেন্ডার করা এবং সব কিছু ওয়্যারিং করার কাজ করে।
কিন্তু আপনি যদি এই UI, নতুন বোতাম, বিভিন্ন পজিশন, বিভিন্ন স্টাইল, টেক্সট ওভারলে কাস্টমাইজ করতে চান, তাহলে কী করবেন?
প্লেয়ার কম্পোজেবল বিল্ডিং ব্লক থেকে তৈরি করা হয়।
আপনি সেগুলি পরিবর্তন করতে পারবেন।
আপনি প্রতিটি আলাদা আলাদা ব্লক কাস্টমাইজ করতে পারেন অথবা আপনার অ্যাপের অন্য কোথাও সেগুলি আলাদাভাবে ব্যবহার করতে পারেন।
যেমন, আপনি উপরের, মাঝের ও bottomControls আলাদাভাবে কাস্টমাইজ করতে পারবেন।
এছাড়াও, ভিডিও না চললে বা কোনও সমস্যা হলে ওভারলেতে শাটার কেমন দেখাবে তা আপনি কাস্টমাইজ করতে পারবেন।
তবে এটি প্রথম স্তর মাত্র।
ডিফল্ট সেন্টার ও bottomControls-এ আরও বিস্তারিত স্লট আছে যা আপনি কাস্টমাইজ করতে পারবেন।
যেমন, আপনি বাকি সবকিছু যেমন আছে তেমন রেখে মাঝের বোতামটি অদলবদল করতে পারেন অথবা স্লাইডারের উপরে বা নিচে এলিমেন্ট যোগ করতে পারেন।
এটি করার জন্য প্রয়োজনীয় সব বিল্ডিং ব্লক Media3 Compose প্রদান করে।
যেমন, আমাদের কাছে অনেক বোতাম আছে, একটি চালান/পজ করুন বোতাম, রিপিট মোড, শাফেল মোড, মিউট বোতাম এবং আরও অনেক কিছু।
তারপর, প্রগ্রেস ইন্ডিকেটর আছে, যেমন স্লাইডার এবং স্ক্রিনে দেখানো পজিশন টেক্সট।
এছাড়াও, বেশ কিছু কন্টেনার ও ওভারলে আছে।
আমি আপনাকে যে হাই-লেভেল প্লেয়ার কম্পোজেবল দেখিয়েছি সেটি একটি উদাহরণ, তবে আরও উদাহরণ আছে, যেমন ত্রুটি ওভারলে বা সাবটাইটেল এবং আরও অনেক কিছু।
এছাড়াও, আমাদের কাছে অন্যান্য উপযোগী কম্পোনেন্ট আছে, যেমন এখানে দেখানো এই মিনি কন্ট্রোলার।
ব্যবহারকারী আপনার অ্যাপে নেভিগেট করার সময় আপনি স্ক্রিনের নিচে অ্যাটাচ করা শিটে এটি রাখতে পারেন।
আর আমরা এখনও শেষ করিনি।
আমরা এই লাইব্রেরি আরও বাড়ানোর জন্য সক্রিয়ভাবে কাজ করছি, যেমন, ক্লিপিং স্লাইডারের মতো নতুন এডিটিং কন্ট্রোল শীঘ্রই আসছে।
এখন, এই বিল্ডিং ব্লকগুলি কীভাবে ব্যবহার করা হয় তা দেখতে এই কাস্টমাইজেশনটি অ্যাকশনে দেখা যাক।
Player(viewModel.exoPlayer)ধরা যাক, আমরা পজিশন ও সময়সীমা সংক্রান্ত টেক্সট স্লাইডারের উপরে নিয়ে যেতে চাই, যা বর্তমানে স্লাইডারের পাশে আছে।
Player(
player = viewModel.exoPlayer,
bottomControls = {
PlayerDefaults.BottomControls(
player,
left = {}, right = {},
above = {
PositionAndDurationText(
player, separator = " • ")
},
)
},
)তাই, আমরা যা করতে পারি তা হল, আমরা এই bottomControls ওভাররাইড করতে পারি।
আমরা এখনও ডিফল্ট কম্পোনেন্ট ব্যবহার করতে পারি, তবে আমরা বাম এবং ডান স্লট খালি সেট করি যাতে সেগুলি অদৃশ্য হয়ে যায়।
এবং এর পরিবর্তে, আমরা এটিকে আরও আকর্ষণীয় দেখাতে একটি কাস্টম বিভাজক সহ উপরের স্লটে এর উপরে অবস্থান এবং সময়কাল সংক্রান্ত টেক্সট রাখি।
এবং এখন, ধরা যাক আমরা centerControls ওভারলে সম্পূর্ণভাবে সরাতে চাই এবং এর পরিবর্তে, স্পিড কন্ট্রোল এবং মিউট বোতাম সহ স্লাইডারের ঠিক উপরে একটি প্লে বোতাম রাখতে চাই।
Player(
player = viewModel.exoPlayer,
centerControls = {},
bottomControls = { ...
above = {
Row(Modifier.fillMaxWidth()) {
PositionAndDurationText(...)
Spacer(Modifier.weight(1f))
PlaybackSpeedToggleButton(player)
MuteButton(player)
PlayPauseButton(player)
}
},
)
}এবং এটি আবার ঠিক একই ধারণা।
আমরা centerControls-কে খালি হিসেবে সেট করতে পারি যাতে সেগুলি অদৃশ্য হয়ে যায় এবং আমরা স্লাইডারের উপরে স্লটটি আরও কিছুটা জায়গা এবং যে তিনটি বোতাম দেখাতে চাই সেগুলি সহ বড় করতে পারি।
মনে রাখবেন, এইসব বোতাম লাইব্রেরি থেকেই পাওয়া যায়, তাই আপনাকে এর জন্য কোনও অতিরিক্ত কোড লিখতে হবে না।
আপনার শুধু এইটুকুই প্রয়োজন।
এবং আপনি এই এলিমেন্টগুলি স্টাইল করার জন্য এই পথ ধরে চলতে পারেন।
আপনি যদি মিউট বোতামের আইকন পরিবর্তন করতে চান, কিন্তু এর কার্যকারিতা একই রাখতে চান, তাহলে এটিও একইভাবে কাজ করে।
Player(
...
bottomControls = { ...
above = {
...
MuteButton(player,
painter = { painterResource(
if (showMuted)
R.drawable.muted
else
R.drawable.unmuted )})
}
},
)আপনি এখানে দেখতে পাচ্ছেন, আপনি বোতামের জন্য কাস্টম পেইন্টার সংজ্ঞায়িত করতে এবং নিজেই আইকন বেছে নিতে পারবেন।
কম্পোনেন্ট আপনাকে কিছু মেটাডেটা প্রদান করে, তাই আপনাকে যা করতে হবে তা হল, সঠিক আইকন বেছে নিতে, এই উদাহরণের showMuted-এর মতো স্ট্যাটাসটি দেখুন।
আর এটাই হল Media3 Compose-এর মূল সুবিধা।
আপনি অ্যাপের লুক ও ফিল নিয়ে চিন্তা করুন, বাকি সব Media3 সামলে নেবে।
এটি প্লেয়ার থেকে স্ট্যাটাস পড়ে, প্লেয়ারের সাথে ইন্টার্যাক্ট করে এবং এর মধ্যে সব ট্রানজিশন ও অ্যানিমেশন ম্যানেজ করে।
এখন UI থেকে মিডিয়া শেয়ার করার বিষয়ে আসা যাক।
একই ডিভাইসে বা রিমোট ডিভাইসে কানেক্ট করা অন্যান্য অ্যাপের সাথে আপনার প্লেব্যাক স্ট্যাটাস শেয়ার করতে পারবেন।
আপনার চলমান প্লেব্যাক প্রকাশ করার প্রধান উপায় হল MediaSession।
এটি আপনার প্লেব্যাকের স্ট্যাটাস ও মেটাডেটা অন্যদের কাছে উপলভ্য করে এবং তাদের আপনার প্লেব্যাক কন্ট্রোল করতে দেয়।
এইভাবে Gemini, সিস্টেম UI মিডিয়া বিজ্ঞপ্তি, Cast, Wear OS বা Android Auto কম্প্যানিয়ন অ্যাপ আপনার অ্যাপের সাথে যোগাযোগ করে।
MediaSession একটি Media3 প্লেয়ারকে র্যাপ করে এবং আপনার কাছে একটি প্লেয়ার থাকলে এটি তৈরি করা খুবই সহজ।
MediaSession.Builder(context, player).build()আবার, এটি ExoPlayer বা আপনার অ্যাপে থাকা অন্য কোনও প্লেয়ার হতে পারে, ঠিক যেমন Compose UI-এর ক্ষেত্রে হয়।
আপনি ব্যাকগ্রাউন্ডে প্লে করলে, সাধারণত এটি MediaSessionService বা MediaLibraryService-এর মধ্যে হোস্ট করবেন, যা অটোমেটিক আপনার জন্য সমস্ত লাইফ সাইকেল এবং বিজ্ঞপ্তির মতো জিনিসও ম্যানেজ করে।
class PlaybackService : MediaSessionService() {
private lateinit var mediaSession:
MediaSession
override fun onGetSession(
info: ControllerInfo) : MediaSession?
= mediaSession
}তবে আপনার যদি কোনও মিডিয়া অ্যাপ থাকে, তাহলে আপনি সম্ভবত ইতিমধ্যেই এই সব জানেন।
আমি আপনাকে যে নতুন জিনিসটি দেখাতে চাই তা হল আমাদের নতুন করে লেখা CastPlayer।
Google Cast-এর মাধ্যমে আপনি লোকাল প্লেব্যাককে Android TV, Chromecast বা স্মার্ট স্পিকারের মতো রিমোট ডিভাইসে ট্রান্সফার করতে পারবেন।
আমরা আগে আলাদা Cast SDK প্রকাশ করতাম, যা এখন রক্ষণাবেক্ষণ মোডে আছে।
পরিবর্তে, Media3 Cast এটিকে সম্পূর্ণরূপে প্রতিস্থাপন করে কারণ এটি অনেক সহজ এবং আরও স্ট্রিমলাইনড ইন্টিগ্রেশন প্রদান করে।
এখানে সবচেয়ে গুরুত্বপূর্ণ এলিমেন্ট হল CastPlayer, যা ExoPlayer-এর মতো একই স্ট্যান্ডার্ড প্লেয়ার ইন্টারফেস প্রয়োগ করে।
ExoPlayer লোকাল প্লেব্যাকের জন্য হলেও, CastPlayer হল একটি ডেলিগেটিং ইনস্ট্যান্স যা ExoPlayer-এর মাধ্যমে লোকালি বা Cast প্রোটোকলের মাধ্যমে রিমোটলি চালাতে পারে।
আর এটি সবকিছুর খেয়াল রাখে।
এটি আউটপুট ডিভাইসের পরিবর্তন লক্ষ্য করে, কানেকশন তৈরি করে, স্ট্যাটাস সিঙ্ক করে এবং প্রয়োজন হলে আপনার জন্য প্লেব্যাক ট্রান্সফার করে।
আর সেই কারণে, আপনার অ্যাপে CastPlayer ইন্টিগ্রেট করা খুবই সহজ।
val player = ExoPlayer.Builder(context).build()
mediaSession = MediaSession.Builder(context,player)
.build()ExoPlayer তৈরি করে এইভাবে MediaSession-এর সাথে শেয়ার করার পরিবর্তে, আপনি CastPlayer ব্যবহার করেন এবং এটাই হল আসল কথা।
Cast.getSingletonInstance(context).initialize()
val player = CastPlayer.Builder(context).build()
mediaSession = MediaSession.Builder(context,player)
.build()আপনার অ্যাপের কোথাও ব্যবহার করার আগে Cast সিস্টেম শুরু করা ছাড়া আর কিছুই করতে হবে না।
মনে রাখবেন যে এই CastPlayer লোকাল প্লেব্যাকের জন্য ইন্টার্নালি একটি ExoPlayer তৈরি করে, তাই লোকাল প্লেয়ারকে আরও কাস্টমাইজ করতে, আপনি নিজের ExoPlayer তৈরি করতে পারেন এবং এই CastPlayer-এ লোকাল প্লেয়ার হিসেবে এটি পাস করতে পারেন।
Cast.getSingletonInstance(context).initialize()
val exoPlayer = ExoPlayer.Builder(context).build()
val player = CastPlayer.Builder(context)
.setLocalPlayer(exoPlayer).build()
mediaSession = MediaSession.Builder(context,player)
.build()এবং এটি আবার একই Media3 নীতি।
আমরা সহজ আউট-অফ-দ্য-বক্স API বিল্ডিং ব্লক প্রদান করি, তবে আরও কাস্টমাইজ করার জন্য আপনার প্রয়োজনীয় সমস্ত কাস্টমাইজেশন বিকল্পও প্রদান করি।
আপনি হয়ত ভাবছেন যে এই সেট-আপে ব্যবহারকারী কীভাবে লোকাল ও রিমোট প্লেব্যাকের মধ্যে পাল্টান।
এটি আগে থেকেই মিডিয়া বিজ্ঞপ্তিতে সিস্টেম আউটপুট সুইচার ডায়ালগের সাথে কাজ করে।
কোণে যে ছোট বোতামটি আছে, সেটি।
কিন্তু আপনি যদি প্লেব্যাক স্ক্রিনে কাস্ট করার বোতাম দেখাতে চান যাতে এটি আরও সহজে খুঁজে পাওয়া যায়, তাহলে কী করবেন?
কয়েক মিনিট আগে আমরা যে কাস্টমাইজ করা Compose UI তৈরি করেছি, সেটি মনে আছে?
Player(
exoPlayer,
centerControls = {}
bottomControls = { /* customized */ },
)এছাড়াও, Media3 Cast একটি আউট-অফ-দ্য-বক্স বোতাম প্রদান করে যা আপনি সেখানে রাখতে পারেন।
উদাহরণস্বরূপ, এটি topControls-এ রেডি-মেড MediaRouteButton যোগ করার মতোই সহজ এবং সেট-আপ করার জন্য আমাদের আর কোনও প্যারামিটারের প্রয়োজন নেই, সত্যিই তাই।
Player(
castPlayer,
centerControls = {}
bottomControls = { /* customized */ },
topControls = {
PlayerDefaults.TopControls(castPlayer) {
MediaRouteButton(
Modifier.align(Alignment.TopEnd))
}
},
)এই বোতামে ক্লিক করলে একই সিস্টেম আউটপুট সুইচার ডায়ালগ খুলে যায় এবং CastPlayer আপনার জন্য প্লেব্যাক ট্রান্সফার করে।
এছাড়াও, আপনি লক্ষ্য করবেন যে আমি CastPlayer-কে এখানে UI-এর সাথে কানেক্ট করেছি যাতে রিমোটলি যা কিছু ঘটছে তা আপনার লোকাল UI-তে দেখা যায়।
আর এর সাথে, আমি ক্রিস্টিনাকে এডিটিং ব্যবহারের কেস সম্পর্কে কথা বলার জন্য হ্যান্ডওভার করছি।
ধন্যবাদ।
হ্যালো, এবার এডিটিং ও উন্নত এফেক্ট সম্পর্কে জেনে নেওয়া যাক।
Media3 API-তে একাধিক কম্পোনেন্ট থাকে।
প্রথমত, Transformer হল আমাদের এডিটিং API-এর প্রধান এন্ট্রি পয়েন্ট।
ট্রান্সফর্মার মিডিয়া প্রসেস, ট্রান্সকোড ও ফাইলে এক্সপোর্ট করে।
এর পরে আছে CompositionPlayer, যা আপনার মিডিয়া কম্পোজিশনের রিয়েল-টাইম প্রিভিউ রেন্ডার করে।
এটি আপনাকে চূড়ান্ত এক্সপোর্ট করার আগে আপনার এডিট প্রিভিউ এবং ফাইন-টিউন করতে দেয়।
তারপর আমাদের কাছে এফেক্ট আছে।
আপনি যখনই সাধারণ ভিজ্যুয়াল এফেক্ট প্রয়োগ করেন বা গ্রাফিক ওভারলে যোগ করেন, তখন এটি আপনাকে ফ্রেম-বাই-ফ্রেম প্রসেসিংয়ের উপর সম্পূর্ণ নিয়ন্ত্রণ দেয়।
সবশেষে, আমাদের কাছে Muxer আছে।
এটি আমাদের পাইপলাইনের চূড়ান্ত আউটপুট স্টেজ হিসেবে কাজ করে, প্রসেস করা অডিও, ভিডিও এবং মেটাডেটা ট্র্যাক গ্রহণ করে এবং সেগুলিকে স্ট্যান্ডার্ডাইজড MP4 কন্টেনারে লেখে।
আমরা গত বছর আমাদের ভিডিও এডিটিং পাইপলাইনকে নতুন করে ভেবেছি এবং নতুন করে তৈরি করেছি এবং আজ আমি প্রধান প্রধান উন্নতিগুলি শেয়ার করতে পেরে আনন্দিত।
আমরা কেন পাইপলাইন আবার তৈরি করেছি?
তাই লিগ্যাসি আর্কিটেকচার বেশ কিছু চ্যালেঞ্জের সম্মুখীন হয়েছে।
প্রথমত, এটি সব প্রসেসিং ধাপ জুড়ে মেটাডেটা প্রচার করতে পারেনি।
এটি OpenGL-এর সাথে গভীরভাবে যুক্ত ছিল, যা আধুনিক গ্রাফিক টুলের জন্য নমনীয়তাকে সীমিত করেছিল।
এবং এর জটিল API-এর কারণে কাস্টমাইজেশন এবং রক্ষণাবেক্ষণ ডেভেলপারদের জন্য একটি কঠিন বাধা হয়ে দাঁড়িয়েছে।
এইসব চ্যালেঞ্জের সমাধান করতে, আমরা একদম নতুন প্রসেসিং পাইপলাইন তৈরি করেছি।
প্রথমত, জটিল মাল্টি-অ্যাসেট কম্পোজিশন অ্যাসেম্বল করা এখন অনেক সহজ।
দ্বিতীয়ত, OpenGL থেকে ডিকাপল করার মাধ্যমে, আপনি WebGPU-এর মতো আধুনিক গ্রাফিক ফ্রেমওয়ার্ক ব্যবহার করার সম্পূর্ণ স্বাধীনতা পান।
এবং অবশেষে, Media3 এখন সরাসরি ডিকোডার এবং এনকোডার ম্যানেজ করে, যা সব ডিভাইস জুড়ে আরও বেশি ধারাবাহিকতা এবং দক্ষতা নিশ্চিত করে।
এই পাইপলাইন কীভাবে কাজ করে তা দেখা যাক।
ডিকোডার, Media3 দ্বারা ম্যানেজ করা হার্ডওয়্যার বাফারে সরাসরি ফ্রেম আউটপুট করে।
ফ্রেম এগ্রিগেটর একাধিক সিকোয়েন্স জুড়ে ফ্রেম সমন্বয় করে, আপনার কাস্টম ফ্রেম প্রসেসরকে এনকোডারে পাঠানোর থেকে সেই বাফারগুলি পড়তে এবং প্রসেস করতে সরাসরি অ্যাক্সেস দেয়।
FrameProcessor ইন্টারফেস অ্যাপ-লেভেল প্রসেসিংয়ের জন্য প্রাথমিক এক্সটেনশন পয়েন্ট হিসেবে কাজ করে।
public interface FrameProcessor
extends AutoCloseable {
interface Listener {
void onWakeup();
void onError(
VideoFrameProcessingException exception);
void onFrameProcessed(
Frame frame,
@Nullable SyncFenceWrapper onCompleteFence);
}
interface Factory {
FrameProcessor create(
FrameWriter output,
Executor listenerExecutor,
Listener listener);
}
boolean queue(List<AsyncFrame> frames);
void signalEndOfStream();
}লিসনার ইন্টারফেসের মাধ্যমে, আপনার অ্যাপ্লিকেশন Media3-কে বিজ্ঞপ্তি দেয় যখনই কোনও ফ্রেম প্রসেস করা হয়, সিঙ্ক্রোনাইজেশন ফেন্স পাস করার সাথে সাথে, যাতে Media3 ঠিকভাবে জানতে পারে কখন বাফার নিরাপদে আবার ব্যবহার করা যেতে পারে।
ইউনিফায়েড মেমরি সম্পর্কে একটি নোট: Media3-কে হার্ডওয়্যার বাফারের মালিকানা দিয়ে, আপনার অ্যাপ সরাসরি ডেটা পড়তে ও পরিবর্তন করতে পারবে।
এই জিরো-কপি পদ্ধতি মেমরি ওভারহেড কমায় এবং প্রসেসিংকে আল্ট্রা-ফাস্ট রাখে।
Adobe হল এমন একজন ডেভেলপার যারা নতুন এডিটিং API-এর সুবিধা নিচ্ছে।
Adobe Premiere টিম তাদের মিডিয়া এডিটিং ইনফ্রাস্ট্রাকচারের ভিত্তি হিসেবে Media3 এডিটিং API ব্যবহার করেছে যাতে Android ইকোসিস্টেম জুড়ে আরও বেশি মানানসই হয়, পাশাপাশি তাদের নিজস্ব কাস্টম পাইপলাইন এবং WebGPU ব্যবহার করার জন্য প্রয়োজনীয় নমনীয়তা বজায় রাখে।
এরপর, আমি আনন্দের সাথে ঘোষণা করছি যে Media3 1.12 রিলিজের অংশ হিসেবে আমরা নতুন এফেক্ট রিলিজ করছি।
ভিডিও এনহ্যান্সমেন্ট দিয়ে শুরু করা।
আমাদের আর্কিটেকচার মডিউলার সেট-আপের উপর নির্ভর করে।
আপনার অ্যাপ্লিকেশন Media3 এফেক্ট Play পরিষেবার সাথে ইন্টিগ্রেট করে, যা Play পরিষেবা এনহ্যান্সমেন্ট মডিউলের সাথে ইন্টারফেস করে।
ভিডিও এনহ্যান্স মডিউলে টোনম্যাপিং, ডিনয়েজিং, ডিব্লারিং এবং সুপার রেজোলিউশন ক্ষমতা অন্তর্ভুক্ত।
আপনার পাইপলাইনে ভিডিও এনহ্যান্স ইন্টিগ্রেট করতে মাত্র কয়েক লাইন কোড লাগে।
val frameProcessorFactory = EnhancementSessionDecorator.Builder(/* context = */ this, baseGlFactory)
.setTonemappingEnabled(true)
.setDeblurAndDenoiseEnabled(true)
.setUpscaleVideoEnabled(true)
.build()
val transformerBuilder = Transformer.Builder(/* context = */ this)
.setFrameProcessorFactory(frameProcessorFactory)EnhancementSessionDecorator.Builder ব্যবহার করে, আপনি টোনম্যাপিং, ডিব্লারিং বা আপস্কেলিংয়ের মতো ক্ষমতা বেছে নিয়ে চালু করতে পারবেন এবং এর ফলে পাওয়া frameProcessorFactory ও হার্ডওয়্যার বাফার হেল্পার Transformer.Builder-এ পাস করতে পারবেন।
Media3 1.12-এ আরেকটি আকর্ষণীয় এফেক্ট আসছে, সেটি হল Studio Sound।
Studio Sound অটোমেটিক আপনার ভিডিওর অডিও ট্র্যাক বিশ্লেষণ করে এবং এটিকে স্পিচ, অ্যাম্বিয়েন্ট নয়েজ ও মিউজিকের মতো আলাদা আলাদা স্টেম হিসেবে ভাগ করে।
ক্রিয়েটররা সহজেই বাতাস বা ভিড়ের কারণে হওয়া বিভ্রান্তি কমাতে পারেন এবং একই সাথে স্পষ্ট কথোপকথন এবং মিউজিককে সামনে আনতে পারেন।
Studio Sound ইন্টিগ্রেট করতে, একটি এফেক্ট অবজেক্টের মধ্যে Studio Sound অডিও প্রসেসর পাস করুন।
val editedMediaItem =
EditedMediaItem.Builder(MediaItem.fromUri(media.uri))
.setEffects(
Effects(
listOf(
soundSeparationAudioProcessor
),
emptyList(), // video effects
)
)
.build()এটি আপনার মিডিয়া আইটেমে অডিও প্রসেসর অ্যাটাচ করে।
Studio Sound অডিও প্রসেসর তৈরি করার সময়, onResult-এর মাধ্যমে বিশ্লেষণ করা অডিও চ্যানেল ম্যাপিং পেতে লিসেনার কলব্যাক অ্যাটাচ করুন।
val soundSeparationAudioProcessor =
SoundSeparationAudioProcessor(
getApplication(),
mainExecutor,
object : SoundSeparationAudioProcessor.Listener {
override fun onResult(channelToAudioType: SparseIntArray) {
for (i in 0 until channelToAudioType.size()) {
val channelIndex = channelToAudioType.keyAt(i)
val audioType = channelToAudioType.valueAt(i)
val label = toAudioTypeName(audioType)
detectedChannelVolumes.add(ChannelVolume(channelIndex, audioType, label))
}
}
},
)অপারেশনের ফলাফল উপলভ্য হলে, চ্যানেল ইনডেক্স, শনাক্ত করা অডিওর ধরন এবং পাঠযোগ্য লেবেল এক্সট্র্যাক্ট করতে প্রতিটি চ্যানেলের মাধ্যমে ইটারেট করুন।
তাহলে, Studio Sound কীভাবে কাজ করে তা শোনা যাক।
তাহলে, প্রথম এফেক্ট। সোনা, কেঁদো না।
আমরা আপনার ডিনারের জন্য কাটছি।
আপনি ব্যাকগ্রাউন্ডে বাচ্চার কান্নার আওয়াজ শুনতে পাবেন এবং এখন এফেক্ট প্রয়োগ করা হয়েছে।
হ্যাঁ, আপনি যেমন শুনতে পাচ্ছেন, ব্যাকগ্রাউন্ডে কোনও বাচ্চার কান্নার আওয়াজ নেই, স্টুডিও সাউন্ড এফেক্টকে ধন্যবাদ।
তাহলে, এখন মেটাডেটা রিট্রিভ করার ব্যাপারে বিস্তারিত আলোচনা করা যাক।
Media3 কীভাবে আপনার জন্য কন্টেনার মেটাডেটা পড়া এবং ফ্রেম এক্সট্র্যাক্ট করা সহজ করে তোলে তা আমরা দেখব।
MetadataRetriever থেকে শুরু করে, এটি ক্লিন, নন-ব্লকিং কোডের জন্য Kotlin coroutines-এর সাথে নির্বিঘ্নে ইন্টিগ্রেট করে।
প্রতিটি মিডিয়া আইটেমের জন্য একটি অপরিবর্তনীয় রিট্রিভার ব্যবহার করে এটি আরও পরিষ্কার, কম ত্রুটি-প্রবণ ডিজাইন প্রদান করে।
এটি সমস্ত API ভার্সন এবং ডিভাইস জুড়ে ধারাবাহিকভাবে কাজ করে।
এবং এটি কোনও অতিরিক্ত কনফিগারেশন ছাড়াই বিভিন্ন ধরনের মিডিয়া ফর্ম্যাট সাপোর্ট করে।
MetadataRetriever ব্যবহার করে একটি বাস্তবিক উদাহরণ এখানে দেওয়া হল।
MetadataRetriever.Builder(context, mediaItem).build().use { retriever ->
// 1. Duration (in microseconds)
val durationUs = retriever.retrieveDurationUs().await()
// 2. Track formats & container metadata (reuses the same preparation pass)
val trackGroups = retriever.retrieveTrackGroups().await()
for (i in 0 until trackGroups.length) {
val format = trackGroups[i].getFormat(0)
// Video/Audio properties: format.width, format.height, format.colorInfo …
// Rich metadata: SlowMotionData, MotionPhotoMetadata, Mp4TimestampData …
val metadata = format.metadata
}
// 3. Stream structure & manifest info
val timeline = retriever.retrieveTimeline().await()
}Kotlin coroutines ব্যবহার করে, আপনি অ্যাসিঙ্ক্রোনাসভাবে সময়কাল, ট্র্যাক ফর্ম্যাট এবং মেটাডেটা পরীক্ষা করতে পারেন, সবই একটি একক, পরিষ্কার ব্লকের মধ্যে।
এখন, FrameExtractor সম্পর্কে কথা বলা যাক।
এটি মিডিয়া আইটেম থেকে ডিকোড করা ভিডিও ফ্রেম দ্রুত ও দক্ষতার সাথে বের করে আনে।
এটি ডিকোডারের মতো অন্তর্নিহিত রিসোর্স অটোমেটিক ম্যানেজ করে, আপনাকে ভিজ্যুয়াল এফেক্ট বা HDR টোন ম্যাপিং প্রয়োগ করতে দেয় এবং আপনাকে ফাইন-গ্রেন সিকিং কন্ট্রোল দেয় যাতে আপনি নিজের প্রয়োজনীয় সঠিক ফ্রেম পেতে পারেন।
কোডে ফ্রেম এক্সট্র্যাকশন কেমন দেখায় তা এখানে দেওয়া হল।
FrameExtractor.Builder(context, mediaItem)
.setSeekParameters(SeekParameters.CLOSEST_SYNC) // Fast keyframe seeking
.setEffects(listOf(Presentation.createForHeight(360))) // GPU downscaling
.setExtractHdrFrames(true) // Optional: HLG HDR or UltraHDR
.build()
.use { extractor ->
// Representative thumbnail
val thumbnail = extractor.getThumbnail().await()
// Frame at specific timestamp (bitmap + actual presentationTimeMs)
val frame = extractor.getFrame(positionMs = 5_000L).await()
}আপনি সিক প্যারামিটার, GPU ডাউনস্কেলিং, এফেক্ট ও HDR সাপোর্টের মতো বিকল্প সহ ইনস্ট্যান্স তৈরি করেন, তারপর ক্লিন সাসপেন্ডিং কল ব্যবহার করে থাম্বনেল ও নির্দিষ্ট ফ্রেমের জন্য অ্যাসিঙ্ক্রোনাসভাবে অপেক্ষা করেন।
আর এখন, ডোনোভানের কাছে।
ধন্যবাদ, ক্রিস্টিনা।
এবার, আমি কিছু অন্তর্নিহিত স্ট্রিমিং টেক সাপোর্ট সম্পর্কে কথা বলতে চাই যা আমরা Media3-তে যোগ করেছি, যার মধ্যে Eclipsa Video এবং Eclipsa Audio-এর মতো ফর্ম্যাটের জন্য সাপোর্ট অন্তর্ভুক্ত।
তাই, Media3-এর মূল লক্ষ্য হল স্ট্রিমিং স্ট্যান্ডার্ডের থেকে এগিয়ে থাকা যাতে প্রতিবার নতুন স্পেসিফিকেশন আসার সময় আপনাকে মিডিয়া পাইপলাইন আবার লিখতে না হয়।
আমরা সম্প্রতি যেসব ফিচার লঞ্চ করেছি তার কয়েকটি উদাহরণ এখানে দেওয়া হল।
আমাদের কন্টেন্ট স্টিয়ারিং আছে, যা স্ট্রিম চলাকালীন ব্যাক এন্ড CDN পাথওয়ে ডায়নামিকভাবে পরিবর্তন করার অনুমতি দেয়।
নির্বিঘ্নে পছন্দমতো বিজ্ঞাপন স্প্লাইস করার জন্য আমাদের কাছে সার্ভার-গাইডেড বিজ্ঞাপন যোগ করার সুবিধা রয়েছে।
এছাড়াও, আমরা সম্পূর্ণ AV1 HDR সাপোর্ট সহ একাধিক এন্ট্রি পয়েন্টে AV1 সাপোর্ট চালু করেছি।
হাই-ফিডেলিটি ক্যাপচার ও এডিটিংয়ের জন্য আমাদের কাছে Android পেশাদার ভিডিওর সাপোর্ট আছে।
এছাড়াও, আমরা JPEG এবং HEIC ফর্ম্যাটে মোশন ফটোর জন্য সহায়তা যোগ করছি।
এবং অবশ্যই, আমরা Eclipsa Video এবং Eclipsa Audio-এর জন্য সহায়তা যোগ করছি, যার ব্যাপারে আমি শীঘ্রই আরও কথা বলব।
আর সুখবর হল, ডিভাইস সাপোর্ট চালু হওয়ার সাথে সাথে এই সবকটি অটোমেটিক কাজ করে।
তাহলে, এখন HDR-এর পরবর্তী বিবর্তন, Eclipsa ভিডিও এবং এটি যে মূল সমস্যাটি সমাধান করার চেষ্টা করছে তা দেখে নেওয়া যাক।
তাই, আগের HDR ফর্ম্যাটগুলি বর্ণনামূলক মেটাডেটা প্রদান করে, তাই তারা নির্ধারণ করে যে দৃশ্যটি কেমন হওয়া উচিত, কিন্তু এটি ডিসপ্লেকে কীভাবে রেন্ডার করতে হবে তা জানায় না।
তাহলে প্রথমে এটি গ্রাউন্ড করা যাক।
বিভিন্ন পরিবেশের জন্য, আপনার স্ক্রিনের গড় উজ্জ্বলতার জন্য বিভিন্ন সাজেশন রয়েছে যাতে আপনি আপনার কন্টেন্ট স্পষ্টভাবে এবং আরামে দেখতে পারেন।
তাই, কম আলো আছে এমন ঘরে, সেই রেঞ্জ ১০০ থেকে ৩০০ নিটের মধ্যে হবে।
এবং তারপরে, অবশ্যই, আপনি যখন আরও উজ্জ্বল পরিবেশে যান, তখন স্ক্রিনকে উজ্জ্বলতা বজায় রাখতে হয় এবং আরও উজ্জ্বল হতে হয় যাতে আপনি নিজের কন্টেন্ট স্পষ্টভাবে দেখতে পারেন, আপনি যখন সরাসরি সূর্যের আলোতে ফোন দেখছেন, তখন স্ক্রিনকে ১,০০০, ২,০০০ বা তারও বেশি নিট পর্যন্ত উজ্জ্বল হতে হতে পারে যাতে আপনি নিজের কন্টেন্ট দেখতে পারেন।
প্রথাগত SDR ১০০ থেকে ৩০০ রেঞ্জে কাজ করে।
এবং অবশ্যই, HDR-এর অর্থ স্ক্রিনকে গ্লোবালি উজ্জ্বল করা নয়।
আপনি ডায়নামিক রেঞ্জ বাড়াতে চান, যাতে আপনার কাছে আগুন এবং সূর্যালোকের মতো জিনিসের জন্য লোকালাইজড হাইলাইট থাকে।
তবে, স্মার্টফোন এই মিক্সের মধ্যে কিছু জটিলতা নিয়ে আসে, কারণ আমরা এগুলি সব জায়গায় সাথে করে নিয়ে যাই, যেমন আমাদের বাড়ির অন্ধকার রুম বা উজ্জ্বল সমুদ্র সৈকত।
এর সাথে, অনেক অ্যাপ SDR UI এলিমেন্টকে SDR কন্টেন্ট এবং HDR কন্টেন্টের সাথে মিক্সড ফিডে মিশিয়ে দেয়, যার ফলে আপনি কখনও কখনও, বিশেষ করে গভীর রাতে স্ক্রল করার সময়, ঝকঝকে, চোখ ধাঁধানো এফেক্ট দেখতে পান।
তাই আমরা বুঝতে পারছি যে HDR কেন এত গুরুত্বপূর্ণ, তাই না?
এটি আমাদের কন্টেন্টকে আরও বেশি পরিবেশে দুর্দান্ত দেখায়।
এমনকি আমরা দেখেছি যে HDR চালু থাকলে ব্যবহারকারীর এনগেজমেন্টও বৃদ্ধি পায়।
কিন্তু সমস্যা হল, বর্তমানে উপলভ্য HDR ফর্ম্যাটগুলি এই ধরনের পরিবেশের কথা মাথায় রেখে তৈরি করা হয়নি।
তাই, Eclipsa Video-র আসল জাদু এখানেই ফুটে ওঠে।
হাসির জন্য পজ করুন।
ধন্যবাদ।
ধন্যবাদ।
তাই, বর্ণনামূলক মেটাডেটার পরিবর্তে, Eclipsa Video প্রেসক্রিপটিভ মেটাডেটা প্রদান করে।
আর এটি তিনটি মূল স্তম্ভের উপর ভিত্তি করে তৈরি করা হয়েছে।
প্রথম স্তম্ভটি হল রেফারেন্স হোয়াইট অ্যাঙ্কর।
তাই এটি ডিসপ্লের অ্যাম্বিয়েন্ট-অ্যাডজাস্ট করা SDR হোয়াইট পয়েন্টে স্ট্যান্ডার্ড উজ্জ্বলতা লক করে, যা উজ্জ্বলতার আকস্মিক বৃদ্ধি দূর করবে।
দ্বিতীয় স্তম্ভ হল ক্রিয়েটর SDR বেসলাইন।
এটি ক্রিয়েটরের সঠিক টোন ম্যাপিং কার্ভ SDR-এ ফিরিয়ে আনে।
তৃতীয়ত, আমাদের কাছে হেডরুম অ্যাডাপ্টিভ গেইন কার্ভ আছে, যা ডিসপ্লের রিয়েল-টাইম HDR হেডরুমের সাথে ম্যাচ করার জন্য হাইলাইটকে নির্ধারকভাবে স্কেল করে যাতে কন্টেন্টটি যে পরিবেশে দেখা হচ্ছে তার সাথে ম্যাচ করে।
এবং এটি Android 17 ও তার পরবর্তী যেকোনও ভার্সনে চলে এমন ডিভাইসে Media3 1.11-এ ExoPlayer আউট-অফ-দ্য-বক্সে উপলভ্য।
এবং Eclipsa Video ক্রস-ইন্ডাস্ট্রি কম্প্যাটিবিলিটির জন্য ওপেন স্ট্যান্ডার্ডের উপর ভিত্তি করে তৈরি করা হয়েছে।
তাই HDR-এর জন্য এর চেয়ে ভাল সময় আর কখনও আসেনি।
অডিওর ক্ষেত্রে, আমাদের কাছে Eclipsa Audio আছে, যা একটি ওপেন-সোর্স, রয়্যালটি-ফ্রি, 3D স্পেশিয়াল অডিও ফর্ম্যাট।
এটি Alliance for Open Media-এর IAMF স্পেসিফিকেশনের উপর ভিত্তি করে তৈরি।
এটি দৃশ্য-ভিত্তিক অ্যাম্বিসনিক্সকে চ্যানেল-ভিত্তিক অডিওর সাথে একত্রিত করে একাধিক মিক্সড প্রেজেন্টেশন সহ একটি একক স্ট্রিমে পরিণত করে।
তাই এটি অবজেক্টের মতো ম্যানিপুলেশন, ডায়ালগ এনহ্যান্সমেন্টের মতো কাজ করতে দেয় এবং এটি স্টিরিও হেডফোন থেকে শুরু করে সারাউন্ড সাউন্ড সেট-আপ পর্যন্ত সব কিছুতেই কাজ করবে।
Media3-তে আসলে দুটি প্লেব্যাক পাথ আছে।
Android 17 এবং তার পরবর্তী ভার্সনের জন্য, ExoPlayer এবং Android Audio Framework অটোমেটিক Eclipsa Audio রেন্ডার করবে।
Android 16 ও তার আগের ভার্সনের জন্য আপনার কাছে এখনও একটি বিকল্প আছে।
আপনি ঐচ্ছিক Media3 অ্যাড-অন লাইব্রেরির মাধ্যমে IAMF এক্সটেনশন চালু করতে পারবেন।
এছাড়াও, আপনি Media3 মাক্সার ব্যবহার করে IAMF অডিও ট্র্যাক লিখতে পারবেন।
তবে, খুব ভাল কোয়ালিটির ফর্ম্যাট সাপোর্ট করাটাই সব নয়।
আমাদের সেই কোয়ালিটি দক্ষতার সাথে প্রদান করতে হবে।
তাই এখন আমি Media3 কীভাবে আমাদের পাইপলাইনগুলিকে আরও দ্রুত এবং আরও দক্ষ করে তুলছে সে সম্পর্কে কথা বলতে চাই।
আজকে আমরা যেসব বিষয় নিয়ে আলোচনা করেছি, তার মধ্যে বেশিরভাগ পারফর্ম্যান্স সংক্রান্ত উন্নতি আপনার Media3 ভার্সন আপ-টু-ডেট রাখার মাধ্যমে সহজেই উপলভ্য হয়।
আমাদের কাছে থাকা একটি ফিচারের উদাহরণ হল PCM অডিও অফলোড, যা অডিও প্লেব্যাককে কম-পাওয়ার প্রসেসিং ইউনিটে রুট করতে পারে।
আমাদের প্রাথমিক বিশ্লেষণে, আমরা স্ক্রিন-অফ অডিও প্লেব্যাকের জন্য ২০% পর্যন্ত পাওয়ার সাশ্রয় দেখেছি।
পিসিএম অডিও অফলোড ছাড়াও, আমাদের কাছে ডায়নামিক শিডিউলিং আছে, যা ExoPlayer-এর ইন্টার্নাল রেন্ডারিং লুপ ওয়েক-আপকে VSYNC এবং ডিকোডার বাফার উপলভ্যতার সাথে অ্যালাইন করে।
এছাড়াও, আমাদের কাছে রেন্ডারার প্রিওয়ার্মিং আছে এবং এটি আপনাকে সেকেন্ডারি ভিডিও রেন্ডারার প্রিওয়ার্ম করার সুবিধা দেয়, যা ইনস্ট্যান্ট প্লেলিস্ট ট্রানজিশন এবং আরও সহজ অ্যাডস্প্লাইসিংয়ের সুবিধা দেবে।
এছাড়াও, আমাদের কাছে স্টাক প্লেয়ার ডিটেকশন এবং প্রি-ক্যাশিং আছে, যা অটোমেটিক স্টলড বাফার এবং রেন্ডারার শনাক্ত করে এবং প্রি-ক্যাশড মেমরি পরিষ্কারভাবে বাউন্ড করে।
আমাদের কাছে আরেকটি অপ্টিমাল মোড আছে, সেটি হল স্ক্রাবিং মোড।
এবং এটি সেইসব অ্যাপের জন্য যেখানে আপনার ব্যবহারকারীরা প্রায়ই কন্টেন্ট স্ক্রাব করেন।
তাই আপনি স্ক্রাবিং মোড চালু করলে, এটি সিকবার টেনে নিয়ে যাওয়াকে আরও বেশি রেসপন্সিভ ও মসৃণ করে তোলে, যেমনটি আপনি এখানে দেখতে পাচ্ছেন।
যাইহোক, এটি স্ক্রাবিং মোড বন্ধ থাকা অবস্থায়।
এবং ডানদিকে, আমরা স্ক্রাবিং মোড চালু দেখতে পাচ্ছি।
ধন্যবাদ।
ধন্যবাদ।
ঠিক আছে।
এখন Android System Health সম্পর্কে কথা বলা যাক।
আমাদের শেয়ার করা RAM, CPU ও ব্যাটারি রিসোর্সের প্রতি আমাদের শ্রদ্ধাশীল হতে হবে এবং Android যেহেতু অডিও হার্ডেনিং ও ফোরগ্রাউন্ড পরিষেবার ক্ষেত্রে নিয়ম আরও কঠোর করছে, তাই যেসব অ্যাপ নিজেদের র পরিষেবা ও বিটম্যাপ ম্যানেজ করছে, সেগুলি প্রায়ই কিছু সমস্যার সম্মুখীন হতে পারে।
আপনি হয়ত ফোরগ্রাউন্ড সার্ভিস শুরু করার অনুমতি না থাকা সংক্রান্ত ব্যতিক্রম বা বাইন্ডার আউট-অফ-মেমরি ব্যতিক্রমের মতো কিছু সমস্যা দেখতে পেয়েছেন।
তাই আমরা মিডিয়া পরিষেবা সেশন ও মিডিয়া বিজ্ঞপ্তি ম্যানেজার এবং আমাদের বিটম্যাপ পাইপলাইনকে বিভিন্ন উপায়ে আরও শক্তিশালী করেছি, যার মধ্যে রয়েছে বাসি ফোরগ্রাউন্ড পরিষেবা ইনটেন্ট প্রতিরোধ করা এবং আর্টওয়ার্ক মেমরি ও এই ধরনের অন্যান্য জিনিসকে সীমাবদ্ধ করা।
তবে, আপনি Media3 ব্যবহার করলে এবং স্ট্যান্ডার্ড নির্দেশিকা অনুসরণ করলে, সিস্টেমের স্বাস্থ্য সংক্রান্ত এইসব বিধিনিষেধ আপনার জন্য কোনও প্রভাব ছাড়াই ম্যানেজ করা হয়।
এবং সবশেষে, আমি Media3-তে শীঘ্রই আসতে চলা একটি ফিচার সম্পর্কে কথা বলতে চাই।
ভিডিও এনকোড বা এক্সপোর্ট করার সময় হার্ডওয়্যারের বৈচিত্র্য সবচেয়ে বড় চ্যালেঞ্জ হতে পারে।
অনেক অ্যাপ একটি সর্বজনীন কোডেক কনফিগারেশন ব্যবহার করে, যা আপনি জানেন, অপ্টিমাইজ না করা কোয়ালিটি এবং পারফর্ম্যান্সের দিকে পরিচালিত করে।
তাই, আমরা CodecDB তৈরি করেছি।
CodecDB, Android ডিভাইস জুড়ে স্ট্যান্ডার্ডাইজড কোয়ালিটি মেট্রিক ও হার্ডওয়্যার বেঞ্চমার্কিং ব্যবহার করে, বাস্তব জগতের ভিডিওর ব্যাপক পরিমাপের উপর ভিত্তি করে তৈরি করা হয়েছে।
তাহলে, এটি কীভাবে কাজ করে তা দেখা যাক।
বাঁদিকে, ফোনে তোলা একটি ভিডিওর ফ্রেম দেখানো হয়েছে, যেখানে আমরা খুব সাধারণ ভিডিও কনফিগারেশন ব্যবহার করেছি যা আমরা অনেক ডিভাইসে ব্যবহার করতে পারি।
এবং ডানদিকে, আমরা ডিভাইস-লেভেল অপ্টিমাল কনফিগারেশন ব্যবহার করেছি যা আমরা CodecDB থেকে পেয়েছি।
তাহলে পার্থক্য কোথায়, তাই তো?
আপনি যদি খুব বেশি ডিটেল আছে এমন অংশ দেখেন, তাহলে কোয়ালিটির সবচেয়ে বড় পার্থক্য দেখতে পাবেন।
তাই গাছের ডালপালা ও ঝোপঝাড়ের স্পষ্টতা বা বিল্ডিংয়ের প্রান্তের তীক্ষ্ণতা দেখুন।
তাই আমরা এখানে যা পাচ্ছি তা হল অনেক ভালো দেখার অভিজ্ঞতা যা CodecDB-এর সুবিধা নিয়ে নির্দিষ্ট ডিভাইসের ক্ষমতার সদ্ব্যবহার করে।
And using CodecDB in code is pretty simple.
val config = CodecDb.onDevice(context)
.forEncodingFallingBackTo {
constraints -> createFallbackConfig(constraints)
}
.findOptimalSettings()
.forEditing()
.withResolution(1920, 1080, /* frameRate= */ 30.0)
.withAnyCodec()
.targetingQuality(VideoEncoder.QUALITY_LEVEL_VERY_GOOD)
.get()আপনি একটি ফ্লুয়েন্ট স্টেজ বিল্ডার প্যাটার্ন ব্যবহার করবেন যা আপনাকে প্রতিটি প্রয়োজনীয় প্যারামিটারের মাধ্যমে গাইড করবে।
তাই আপনি আপনার ব্যবহারের ধরন নির্দিষ্ট করবেন।
এখানে আমরা এডিট করার জন্য ব্যবহার করছি।
এটি CodecDB-কে জানায় যে আপনি Media3 এক্সপোর্ট বা ট্রান্সকোডিং পাইপলাইন ব্যবহার করছেন।
আপনি অন্য কিছু ব্যবহারের ক্ষেত্রেও এটি সেট করতে পারেন, যেমন, আপনি যদি ক্যামেরা ক্যাপচার করার জন্য এটি ব্যবহার করেন।
এছাড়াও, আপনি টার্গেট রেজোলিউশন ও ফ্রেমরেট পাস করবেন।
তারপর, 1080p ভিডিওর জন্য প্রতি সেকেন্ডে ৮ মেগাবিট নাকি ১৫ মেগাবিট প্রয়োজন তা অনুমান করার পরিবর্তে, আপনি CodecDB-কে জানান যে আপনি কোন কোডেক ব্যবহার করতে চান এবং আপনি একটি পারসেপচুয়াল কোয়ালিটি টার্গেট চান।
এই ক্ষেত্রে, আমরা খুব ভালো কোয়ালিটি লেভেল ব্যবহার করছি।
CodecDB সেই SOC-এর জন্য অভিজ্ঞতামূলক বেঞ্চমার্ক কার্ভ দেখে এবং আদর্শ কোডেক ও এনকোডার প্যারামিটার প্রদান করে।
আমরা আশা করি যে CodecDB খুব শীঘ্রই Media3-তে লঞ্চ হবে এবং যখন এটি হবে, তখন এটি নেটিভ Media3 প্রকার ব্যবহার করবে।
তাই আপনার আগে থেকে থাকা Media3 কোডের সাথে এটি ইন্টিগ্রেট করা খুব সহজ হবে।
ঠিক আছে।
আজ আমরা Media3-তে অনেক দুর্দান্ত কার্যকারিতা দেখেছি, তাই আসুন রিক্যাপ করি।
আজ, আপনি আমাদের নতুন Compose UI মডিউল, নতুন CastPlayer, নতুনভাবে সাজানো এডিটিং পাইপলাইন এবং Media3-তে ব্যবহার করতে পারবেন এমন অনেক নতুন এফেক্ট সম্পর্কে জেনেছেন।
এছাড়াও, মেটাডেটা ও ফ্রেম ফিরিয়ে আনার জন্য আমরা নতুন টুল দেখেছি।
এবং আমরা নতুন স্ট্রিমিং প্রযুক্তি সহায়তা এবং পারফর্ম্যান্স এনহ্যান্সমেন্ট ও ইউটিলিটি দেখেছি।
Media3 হল একটি ওপেন সোর্স লাইব্রেরি, তাই আপনি আসলে দেখতে পারবেন যে আমরা কীভাবে আমাদের GitHub রিপোজিটরিতে এইসব ফিচার প্রয়োগ করেছি।
আজকের তারিখ পর্যন্ত, Media3-এর লেটেস্ট স্টেবল রিলিজ হল 1.11.1।
এছাড়াও, আপনি 1.12.0 ভার্সন চেক করে দেখতে পারেন, যা বর্তমানে আলফা ভার্সনে রয়েছে।
এবং এই শর্ট লিঙ্কটি ফলো করুন, যা আপনাকে Media3-এ আমাদের ডেভেলপার ডকুমেন্টেশনে নিয়ে যাবে।
আপনাকে অনেক ধন্যবাদ এবং ADS-এর বাকি অংশ উপভোগ করুন।
@Composable
fun videoScreen() {
Player(viewModel.exoPlayer)
}Player(viewModel.exoPlayer)Player(
player = viewModel.exoPlayer,
bottomControls = {
PlayerDefaults.BottomControls(
player,
left = {}, right = {},
above = {
PositionAndDurationText(
player, separator = " • ")
},
)
},
)Player(
player = viewModel.exoPlayer,
centerControls = {},
bottomControls = { ...
above = {
Row(Modifier.fillMaxWidth()) {
PositionAndDurationText(...)
Spacer(Modifier.weight(1f))
PlaybackSpeedToggleButton(player)
MuteButton(player)
PlayPauseButton(player)
}
},
)
}Player(
...
bottomControls = { ...
above = {
...
MuteButton(player,
painter = { painterResource(
if (showMuted)
R.drawable.muted
else
R.drawable.unmuted )})
}
},
)MediaSession.Builder(context, player).build()class PlaybackService : MediaSessionService() {
private lateinit var mediaSession:
MediaSession
override fun onGetSession(
info: ControllerInfo) : MediaSession?
= mediaSession
}val player = ExoPlayer.Builder(context).build()
mediaSession = MediaSession.Builder(context,player)
.build()Cast.getSingletonInstance(context).initialize()
val player = CastPlayer.Builder(context).build()
mediaSession = MediaSession.Builder(context,player)
.build()Cast.getSingletonInstance(context).initialize()
val exoPlayer = ExoPlayer.Builder(context).build()
val player = CastPlayer.Builder(context)
.setLocalPlayer(exoPlayer).build()
mediaSession = MediaSession.Builder(context,player)
.build()Player(
exoPlayer,
centerControls = {}
bottomControls = { /* customized */ },
)Player(
castPlayer,
centerControls = {}
bottomControls = { /* customized */ },
topControls = {
PlayerDefaults.TopControls(castPlayer) {
MediaRouteButton(
Modifier.align(Alignment.TopEnd))
}
},
)public interface FrameProcessor
extends AutoCloseable {
interface Listener {
void onWakeup();
void onError(
VideoFrameProcessingException exception);
void onFrameProcessed(
Frame frame,
@Nullable SyncFenceWrapper onCompleteFence);
}
interface Factory {
FrameProcessor create(
FrameWriter output,
Executor listenerExecutor,
Listener listener);
}
boolean queue(List<AsyncFrame> frames);
void signalEndOfStream();
}val frameProcessorFactory = EnhancementSessionDecorator.Builder(/* context = */ this, baseGlFactory)
.setTonemappingEnabled(true)
.setDeblurAndDenoiseEnabled(true)
.setUpscaleVideoEnabled(true)
.build()
val transformerBuilder = Transformer.Builder(/* context = */ this)
.setFrameProcessorFactory(frameProcessorFactory)val editedMediaItem =
EditedMediaItem.Builder(MediaItem.fromUri(media.uri))
.setEffects(
Effects(
listOf(
soundSeparationAudioProcessor
),
emptyList(), // video effects
)
)
.build()val soundSeparationAudioProcessor =
SoundSeparationAudioProcessor(
getApplication(),
mainExecutor,
object : SoundSeparationAudioProcessor.Listener {
override fun onResult(channelToAudioType: SparseIntArray) {
for (i in 0 until channelToAudioType.size()) {
val channelIndex = channelToAudioType.keyAt(i)
val audioType = channelToAudioType.valueAt(i)
val label = toAudioTypeName(audioType)
detectedChannelVolumes.add(ChannelVolume(channelIndex, audioType, label))
}
}
},
)MetadataRetriever.Builder(context, mediaItem).build().use { retriever ->
// 1. Duration (in microseconds)
val durationUs = retriever.retrieveDurationUs().await()
// 2. Track formats & container metadata (reuses the same preparation pass)
val trackGroups = retriever.retrieveTrackGroups().await()
for (i in 0 until trackGroups.length) {
val format = trackGroups[i].getFormat(0)
// Video/Audio properties: format.width, format.height, format.colorInfo …
// Rich metadata: SlowMotionData, MotionPhotoMetadata, Mp4TimestampData …
val metadata = format.metadata
}
// 3. Stream structure & manifest info
val timeline = retriever.retrieveTimeline().await()
}FrameExtractor.Builder(context, mediaItem)
.setSeekParameters(SeekParameters.CLOSEST_SYNC) // Fast keyframe seeking
.setEffects(listOf(Presentation.createForHeight(360))) // GPU downscaling
.setExtractHdrFrames(true) // Optional: HLG HDR or UltraHDR
.build()
.use { extractor ->
// Representative thumbnail
val thumbnail = extractor.getThumbnail().await()
// Frame at specific timestamp (bitmap + actual presentationTimeMs)
val frame = extractor.getFrame(positionMs = 5_000L).await()
}val config = CodecDb.onDevice(context)
.forEncodingFallingBackTo {
constraints -> createFallbackConfig(constraints)
}
.findOptimalSettings()
.forEditing()
.withResolution(1920, 1080, /* frameRate= */ 30.0)
.withAnyCodec()
.targetingQuality(VideoEncoder.QUALITY_LEVEL_VERY_GOOD)
.get()