TextureView

TextureView ক্লাস হল একটি ভিউ অবজেক্ট যা SurfaceTexture-এর সাথে ভিউকে একত্রিত করে।

OpenGL ES-এর মাধ্যমে রেন্ডার করুন

TextureView অবজেক্ট SurfaceTexture-কে র‍্যাপ করে, কলব্যাকে রেসপন্স করে এবং নতুন বাফার অ্যাকোয়ার করে। কোনও TextureView অবজেক্ট নতুন বাফার পেলে, TextureView একটি ভিউ ইনভ্যালিডেট করার অনুরোধ জানায় এবং সেটির ডেটা সোর্স হিসেবে সবচেয়ে নতুন বাফারের কন্টেন্ট ব্যবহার করে ড্র করে, ভিউ স্টেট যেখানে এবং যেভাবে দেখানো উচিত বলে নির্দেশ করে, সেখানে এবং সেভাবেই রেন্ডার করে।

OpenGL ES (GLES) EGL তৈরির কলে SurfaceTexture পাস করে TextureView অবজেক্টে রেন্ডার করতে পারে, কিন্তু এটি সমস্যা তৈরি করে। GLES যখন TextureView-এ রেন্ডার করে, তখন BufferQueue প্রোডিউসার ও কনজিউমার একই থ্রেডে থাকে, যার ফলে বাফার সোয়াপ কল স্টল বা ব্যর্থ হতে পারে। যেমন, কোনও প্রোডিউসর UI থ্রেড থেকে খুব দ্রুত একের পর এক একাধিক বাফার জমা দিলে, EGL বাফার অদল-বদল কলকে BufferQueue থেকে একটি বাফার ডিকিউ করতে হবে। তবে, কনজিউমার ও প্রোডিউসার একই থ্রেডে থাকার কারণে, কোনও বাফার উপলভ্য থাকবে না এবং সোয়াপ কল হ্যাং হয়ে যাবে বা ব্যর্থ হবে।

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

SurfaceView বা TextureView বেছে নিন

SurfaceView ও TextureView একই ধরনের ভূমিকা পালন করে এবং দু'টিই ভিউ হায়ারার্কির সিটিজেন। তবে, SurfaceView এবং TextureView-এর আলাদা প্রয়োগ আছে। SurfaceView অবজেক্ট অন্যান্য ভিউয়ের মতো একই প্যারামিটার নেয়, কিন্তু রেন্ডার করার সময় SurfaceView কন্টেন্ট ট্রান্সপারেন্ট হয়।

TextureView-এর আলফা ও রোটেশন ম্যানেজমেন্ট SurfaceView-এর থেকে ভালো, কিন্তু ভিডিওর উপরে লেয়ার করা UI এলিমেন্ট কম্পোজিট করার সময় SurfaceView-এর পারফর্ম্যান্স ভালো হয়। কোনও ক্লায়েন্ট SurfaceView অবজেক্টের মাধ্যমে রেন্ডার করলে, SurfaceView ক্লায়েন্টকে আলাদা কম্পোজিশন লেয়ার প্রদান করে। ডিভাইসে কাজ করলে, SurfaceFlinger হার্ডওয়্যার ওভারলে হিসেবে আলাদা লেয়ার কম্পোজ করে। কোনও ক্লায়েন্ট TextureView-এর মাধ্যমে রেন্ডার করলে, UI টুলকিট TextureView অবজেক্টের কন্টেন্টকে GPU-এর মাধ্যমে ভিউ হায়ারার্কিতে কম্পোজিট করে। কন্টেন্টে আপডেট করলে অন্যান্য ভিউ এলিমেন্ট আবার আঁকতে হতে পারে, যেমন, অন্যান্য ভিউ যদি TextureView-এর উপরে পজিশন করা থাকে। ভিউ রেন্ডারিং সম্পূর্ণ হওয়ার পরে, SurfaceFlinger অ্যাপ UI লেয়ার ও অন্যান্য সব লেয়ার কম্পোজিট করে, যাতে প্রতিটি দৃশ্যমান পিক্সেল দু'বার কম্পোজিট হয়।

কেস স্টাডি: Grafika-এর 'ভিডিও চালান'

Grafika-এর Play Video-তে দুটি ভিডিও প্লেয়ারের পেয়ার থাকে, একটি TextureView-এর সাথে এবং অন্যটি SurfaceView-এর সাথে প্রয়োগ করা হয়। অ্যাক্টিভিটির ভিডিও ডিকোডিং অংশ TextureView এবং SurfaceView, উভয়ের জন্যই MediaCodec থেকে সারফেসে ফ্রেম পাঠায়। ইমপ্লিমেন্টেশনের মধ্যে সবচেয়ে বড় পার্থক্য হল, সঠিক অ্যাস্পেক্ট রেশিও দেখানোর জন্য প্রয়োজনীয় ধাপ।

SurfaceView স্কেল করার জন্য FrameLayout-এর কাস্টম ইমপ্লিমেন্টেশন প্রয়োজন। WindowManager-কে SurfaceFlinger-এ নতুন উইন্ডো পজিশন ও নতুন সাইজ ভ্যালু পাঠাতে হবে। TextureView অবজেক্টের SurfaceTexture স্কেলিং করার জন্য TextureView#setTransform() সহ ট্রান্সফর্মেশন ম্যাট্রিক্স কনফিগার করতে হবে।

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

কেস স্টাডি: Grafika-এর ডবল ডিকোড

Grafika-এর ডবল ডিকোড TextureView-এর মধ্যে SurfaceTexture-এর ম্যানিপুলেশন দেখায়।

Grafika-এর ডবল ডিকোড, ভিডিও কনফারেন্সিং অ্যাপের মতো পাশাপাশি দুটি ভিডিও চালানোর জন্য একজোড়া TextureView অবজেক্ট ব্যবহার করে। স্ক্রিনের ওরিয়েন্টেশন পরিবর্তিত হলে এবং অ্যাক্টিভিটি আবার চালু হলে, MediaCodec ডিকোডার বন্ধ হয় না, এর ফলে রিয়েল-টাইম ভিডিও স্ট্রিম প্লেব্যাক করা যায়। দক্ষতা উন্নত করতে, ক্লায়েন্টকে সারফেস চালু রাখতে হবে। সারফেস হল SurfaceTexture-এর BufferQueue-এ প্রডিউসার ইন্টারফেসের একটি হ্যান্ডেল। যেহেতু TextureView অবজেক্ট SurfaceTexture ম্যানেজ করে, তাই ক্লায়েন্টকে SurfaceTexture চালু রাখতে হবে যাতে সারফেস চালু থাকে।

SurfaceTexture চালু রাখতে, Grafika-এর Double Decode TextureView অবজেক্ট থেকে SurfaceTextures-এর রেফারেন্স সংগ্রহ করে এবং সেগুলি একটি স্ট্যাটিক ফিল্ডে সেভ করে। তারপরে, SurfaceTexture যাতে ধ্বংস না হয়ে যায়, সেই জন্য Grafika-এর ডবল ডিকোড false থেকে TextureView.SurfaceTextureListener#onSurfaceTextureDestroyed()-এ ফিরে আসে। TextureView তারপরে onSurfaceTextureDestroyed()-কে একটি SurfaceTexture পাস করে যা অ্যাক্টিভিটি কনফিগারেশন পরিবর্তন জুড়ে মেইনটেন করা যেতে পারে, যা ক্লায়েন্ট setSurfaceTexture()-এর মাধ্যমে নতুন TextureView অবজেক্টে পাস করে।

আলাদা থ্রেড প্রতিটি ভিডিও ডিকোডার চালায়। Mediaserver, BufferQueue কনজিউমার SurfaceTextures-এ ডিকোড করা আউটপুট সহ বাফার পাঠায়। TextureView অবজেক্ট রেন্ডারিং পারফর্ম করে এবং UI থ্রেডে এক্সিকিউট করে।

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