মনে রাখবেন: এই পৃষ্ঠা Camera2 প্যাকেজকে রেফার করে। আপনার অ্যাপের জন্য Camera2 থেকে নির্দিষ্ট, লো-লেভেল ফিচারের প্রয়োজন না হলে, আমরা CameraX ব্যবহার করার সাজেশন দিই। CameraX এবং Camera2, দুটিই Android 5.0 (API লেভেল ২১) এবং তার পরবর্তী যেকোনও ভার্সনে কাজ করে।
Android ডিভাইসে ক্যামেরা এবং ক্যামেরা প্রিভিউ সবসময় একই ওরিয়েন্টেশনে থাকে না।
ডিভাইসটি ফোন, ট্যাবলেট বা কম্পিউটার যাই হোক না কেন, ডিভাইসে ক্যামেরা একটি নির্দিষ্ট অবস্থানে থাকে। ডিভাইসের ওরিয়েন্টেশন পরিবর্তন হলে, ক্যামেরার ওরিয়েন্টেশন পরিবর্তন হয়।
ফলস্বরূপ, ক্যামেরা অ্যাপ সাধারণত ডিভাইসের ওরিয়েন্টেশন ও ক্যামেরা প্রিভিউয়ের অ্যাস্পেক্ট রেশিওর মধ্যে একটি নির্দিষ্ট সম্পর্ক আছে বলে ধরে নেয়। ফোন পোর্ট্রেট ওরিয়েন্টেশনে থাকলে, ক্যামেরার প্রিভিউ চওড়ার চেয়ে লম্বা হবে বলে ধরে নেওয়া হয়। ফোন (এবং ক্যামেরা) ল্যান্ডস্কেপ মোডে ঘোরানো হলে, ক্যামেরা প্রিভিউ লম্বার চেয়ে চওড়া হবে বলে আশা করা হচ্ছে।
তবে, নতুন ফর্ম ফ্যাক্টর, যেমন ফোল্ডেবল ডিভাইস এবং ডিসপ্লে মোড, যেমন মাল্টি‑উইন্ডো ও মাল্টি‑ডিসপ্লে-এর ক্ষেত্রে এই অনুমানগুলি চ্যালেঞ্জের মুখে পড়ে। ফোল্ডেবল ডিভাইস ওরিয়েন্টেশন পরিবর্তন না করেই ডিসপ্লে সাইজ এবং অ্যাস্পেক্ট রেশিও পরিবর্তন করে। মাল্টি‑উইন্ডো মোড ক্যামেরা অ্যাপকে স্ক্রিনের একটি অংশে সীমাবদ্ধ করে, ডিভাইসের ওরিয়েন্টেশন যাই হোক না কেন, ক্যামেরা প্রিভিউ স্কেল করে। মাল্টি‑ডিসপ্লে মোড সেকেন্ডারি ডিসপ্লে ব্যবহার করার সুবিধা দেয়, যা প্রাইমারি ডিসপ্লের মতো একই ওরিয়েন্টেশনে নাও থাকতে পারে।
ক্যামেরার অভিমুখ
Android কম্প্যাটিবিলিটি ডেফিনেশন অনুযায়ী, ক্যামেরার ইমেজ সেন্সর "এমনভাবে ওরিয়েন্ট করতে হবে যাতে ক্যামেরার দীর্ঘ ডাইমেনশন স্ক্রিনের দীর্ঘ ডাইমেনশনের সাথে অ্যালাইন করে। অর্থাৎ, ডিভাইসটি ল্যান্ডস্কেপ ওরিয়েন্টেশনে ধরা হলে, ক্যামেরা অবশ্যই ল্যান্ডস্কেপ ওরিয়েন্টেশনে ছবি ক্যাপচার করবে। ডিভাইসের স্বাভাবিক ওরিয়েন্টেশন যাই হোক না কেন, এটি প্রযোজ্য হবে; অর্থাৎ, ল্যান্ডস্কেপ-প্রাইমারি ডিভাইসের পাশাপাশি পোর্ট্রেট-প্রাইমারি ডিভাইসের ক্ষেত্রেও এটি প্রযোজ্য হবে।"
ক্যামেরা থেকে স্ক্রিনের বিন্যাস ক্যামেরা অ্যাপে ক্যামেরা ভিউফাইন্ডারের ডিসপ্লে এরিয়াকে সর্বাধিক করে। এছাড়াও, ইমেজ সেন্সর সাধারণত ল্যান্ডস্কেপ অ্যাস্পেক্ট রেশিওতে তাদের ডেটা আউটপুট করে, ৪:৩ সবচেয়ে সাধারণ।
ক্যামেরা সেন্সরের স্বাভাবিক ওরিয়েন্টেশন হল ল্যান্ডস্কেপ। ছবি ১-এ, ফ্রন্ট-ফেসিং ক্যামেরার (ডিসপ্লে যেদিকে, ক্যামেরা সেদিকেই পয়েন্ট করে) সেন্সর ফোনের সাপেক্ষে ২৭০ ডিগ্রি ঘোরানো হয়েছে যাতে Android কম্প্যাটিবিলিটি ডেফিনেশন মেনে চলা যায়।
অ্যাপে সেন্সর রোটেশন এক্সপোজ করতে, camera2 API-তে
SENSOR_ORIENTATION কনস্ট্যান্ট অন্তর্ভুক্ত থাকে। বেশিরভাগ ফোন ও ট্যাবলেটের ক্ষেত্রে, ডিভাইস ফ্রন্ট-ফেসিং ক্যামেরার জন্য ২৭০ ডিগ্রি এবং ব্যাক-ফেসিং ক্যামেরার জন্য ৯০ ডিগ্রি (ডিভাইসের পিছন থেকে দেখার পয়েন্ট) সেন্সর ওরিয়েন্টেশন রিপোর্ট করে, যা সেন্সরের লম্বা প্রান্তকে ডিভাইসের লম্বা প্রান্তের সাথে অ্যালাইন করে। ল্যাপটপের ক্যামেরা সাধারণত ০ বা ১৮০ ডিগ্রির সেন্সর ওরিয়েন্টেশন
রিপোর্ট করে।
ক্যামেরা ইমেজ সেন্সর তার ডেটা (ইমেজ বাফার) সেন্সরের স্বাভাবিক ওরিয়েন্টেশনে (ল্যান্ডস্কেপ)
আউটপুট করে, তাই ডিভাইসের স্বাভাবিক ওরিয়েন্টেশনে ক্যামেরা প্রিভিউ সোজাভাবে
দেখানোর জন্য ইমেজ বাফারকে SENSOR_ORIENTATION-এর মাধ্যমে নির্দিষ্ট করা ডিগ্রি অনুযায়ী
ঘোরাতে হবে। সামনের ক্যামেরার ক্ষেত্রে,
ঘড়ির কাঁটার বিপরীতে এবং পিছনের ক্যামেরার ক্ষেত্রে, ঘড়ির কাঁটার দিকে ঘোরানো হয়।
যেমন, চিত্র ১-এ ফ্রন্ট-ফেসিং ক্যামেরার জন্য, ক্যামেরা সেন্সর দ্বারা তৈরি ইমেজ বাফার এইরকম দেখতে হয়:
ছবিটি ঘড়ির কাঁটার বিপরীতে ২৭০ ডিগ্রি ঘোরাতে হবে যাতে প্রিভিউয়ের ওরিয়েন্টেশন ডিভাইসের ওরিয়েন্টেশনের সাথে মেলে:
একটি ব্যাক-ফেসিং ক্যামেরা আগের বাফারের মতো একই ওরিয়েন্টেশন সহ একটি ইমেজ বাফার তৈরি করবে, কিন্তু SENSOR_ORIENTATION হল ৯০ ডিগ্রি। এর ফলে, বাফার ঘড়ির কাঁটার দিকে ৯০ ডিগ্রি ঘোরানো হয়।
ডিভাইসের ঘূর্ণন
ডিভাইস রোটেশন হল, কোনও ডিভাইস তার স্বাভাবিক ওরিয়েন্টেশন থেকে কত ডিগ্রি ঘোরানো হয়েছে। যেমন, ল্যান্ডস্কেপ ওরিয়েন্টেশনে থাকা ফোন, ঘোরানোর দিকের উপর নির্ভর করে, ৯০ বা ২৭০ ডিগ্রি ঘোরে।
ক্যামেরা প্রিভিউ যাতে সোজা দেখায়, তার জন্য ক্যামেরা সেন্সর ইমেজ বাফারকে ডিভাইস রোটেশনের (সেন্সর ওরিয়েন্টেশনের ডিগ্রির সাথে) সমান ডিগ্রিতে ঘোরাতে হবে।
ওরিয়েন্টেশন ক্যালকুলেশন
ক্যামেরা প্রিভিউয়ের সঠিক ওরিয়েন্টেশন সেন্সর ওরিয়েন্টেশন ও ডিভাইস রোটেশন বিবেচনা করে।
সেন্সর ইমেজ বাফারের সামগ্রিক রোটেশন নিম্নলিখিত ফর্মুলা ব্যবহার করে গণনা করা যেতে পারে:
rotation = (sensorOrientationDegrees - deviceOrientationDegrees * sign + 360) % 360
যেখানে sign হল ফ্রন্ট-ফেসিং ক্যামেরার জন্য 1, ব্যাক-ফেসিং ক্যামেরার জন্য -1।
সামনের ক্যামেরার জন্য, ইমেজ বাফার ঘড়ির কাঁটার বিপরীতে ঘোরানো হয় (সেন্সরের স্বাভাবিক ওরিয়েন্টেশন থেকে)। ব্যাক-ফেসিং ক্যামেরার ক্ষেত্রে, সেন্সর ইমেজ বাফার ঘড়ির কাঁটার দিকে ঘোরানো হয়।
deviceOrientationDegrees * sign + 360 এক্সপ্রেশনটি রিয়ার ক্যামেরার জন্য ডিভাইসের রোটেশনকে
ঘড়ির কাঁটার বিপরীত দিক থেকে ঘড়ির কাঁটার দিকে কনভার্ট করে (যেমন,
ঘড়ির কাঁটার বিপরীত দিকে ২৭০ ডিগ্রি থেকে ঘড়ির কাঁটার দিকে ৯০ ডিগ্রিতে কনভার্ট করা)। মডিউলো
অপারেশন ফলাফলকে ৩৬০ ডিগ্রির কম স্কেল করে (যেমন, ৫৪০
ডিগ্রি রোটেশনকে ১৮০ ডিগ্রিতে স্কেল করা)।
বিভিন্ন API ডিভাইসের রোটেশন আলাদাভাবে রিপোর্ট করে:
Display#getRotation()ডিভাইসের ঘড়ির কাঁটার বিপরীতে ঘূর্ণন প্রদান করে (ব্যবহারকারীর দৃষ্টিকোণ থেকে)। এই ভ্যালু আগের ফর্মুলায় যেমন আছে তেমনভাবেই প্লাগ-ইন করা হয়।OrientationEventListener#onOrientationChanged()ডিভাইসের ঘড়ির কাঁটার দিকে ঘূর্ণন (ব্যবহারকারীর দৃষ্টিকোণ থেকে) ফেরত দেয়। আগের ফর্মুলায় ব্যবহার করার জন্য ভ্যালু নেগেট করুন।
সামনের দিকের ক্যামেরা
ছবি ৪-এ ক্যামেরা সেন্সর দ্বারা তৈরি করা ইমেজ বাফার এখানে দেওয়া হল:
সেন্সর ওরিয়েন্টেশন অ্যাডজাস্ট করার জন্য বাফারকে ঘড়ির কাঁটার বিপরীতে ২৭০ ডিগ্রি ঘোরাতে হবে (উপরে ক্যামেরা ওরিয়েন্টেশন দেখুন):
তারপর, ডিভাইসের রোটেশন বিবেচনা করার জন্য বাফারটি ঘড়ির কাঁটার বিপরীত দিকে অতিরিক্ত ৯০ ডিগ্রি ঘোরানো হয়, যার ফলে চিত্র ৪-এ ক্যামেরা প্রিভিউয়ের সঠিক ওরিয়েন্টেশন হয়:
এখানে ক্যামেরাটি ডানদিকে ল্যান্ডস্কেপ ওরিয়েন্টেশনে ঘোরানো হয়েছে:
এখানে ছবির বাফার দেওয়া হল:
সেন্সর ওরিয়েন্টেশন অ্যাডজাস্ট করতে বাফারকে ঘড়ির কাঁটার বিপরীতে ২৭০ ডিগ্রি ঘোরাতে হবে:
তারপর, ডিভাইসের রোটেশন বিবেচনা করার জন্য বাফারটি ঘড়ির কাঁটার বিপরীতে আরও ২৭০ ডিগ্রি ঘোরানো হয়:
পিছনের ক্যামেরা
পিছনের ক্যামেরার সেন্সর সাধারণত ৯০ ডিগ্রিতে (ডিভাইসের পিছন থেকে দেখলে) ওরিয়েন্ট করা থাকে। ক্যামেরা প্রিভিউ ওরিয়েন্ট করার সময়, সেন্সর ইমেজ বাফার সেন্সর রোটেশনের পরিমাণ অনুযায়ী ঘড়ির কাঁটার দিকে রোটেট করা হয় (ফ্রন্ট-ফেসিং ক্যামেরার মতো ঘড়ির কাঁটার বিপরীতে নয়) এবং তারপর ইমেজ বাফার ডিভাইস রোটেশনের পরিমাণ অনুযায়ী ঘড়ির কাঁটার বিপরীতে রোটেট করা হয়।
১২ নম্বর চিত্রে ক্যামেরা সেন্সর থেকে পাওয়া ইমেজ বাফার এখানে দেওয়া হল:
সেন্সর ওরিয়েন্টেশন অ্যাডজাস্ট করার জন্য বাফারটি ঘড়ির কাঁটার দিকে ৯০ ডিগ্রি ঘোরাতে হবে:
তারপর, ডিভাইসের রোটেশন অনুযায়ী বাফার ঘড়ির কাঁটার বিপরীতে ২৭০ ডিগ্রি ঘোরানো হয়:
অ্যাস্পেক্ট রেশিও
ডিভাইসের ওরিয়েন্টেশন পরিবর্তন হলে ডিসপ্লের অ্যাস্পেক্ট রেশিও পরিবর্তন হয়, তবে ফোল্ডেবল ডিভাইস ফোল্ড ও আনফোল্ড করলে, মাল্টি-উইন্ডো এনভায়রনমেন্টে উইন্ডোর সাইজ পরিবর্তন করলে এবং সেকেন্ডারি ডিসপ্লেতে অ্যাপ খুললে, ডিসপ্লের অ্যাস্পেক্ট রেশিও পরিবর্তন হয়।
ক্যামেরা সেন্সর ইমেজ বাফারকে ভিউফাইন্ডার UI এলিমেন্টের ওরিয়েন্টেশন ও অ্যাস্পেক্ট রেশিওর সাথে ম্যাচ করার জন্য ওরিয়েন্ট ও স্কেল করতে হবে, কারণ UI ডায়নামিকভাবে ওরিয়েন্টেশন পরিবর্তন করে—ডিভাইস ওরিয়েন্টেশন পরিবর্তন করুক বা না করুক।
নতুন ফর্ম ফ্যাক্টর বা মাল্টি-উইন্ডো বা মাল্টি-ডিসপ্লে পরিবেশে, আপনার অ্যাপ যদি ধরে নেয় যে ক্যামেরা প্রিভিউয়ের ওরিয়েন্টেশন ডিভাইসের ওরিয়েন্টেশনের (পোর্ট্রেট বা ল্যান্ডস্কেপ) মতোই, তাহলে আপনার প্রিভিউ ভুলভাবে ওরিয়েন্টেড, ভুলভাবে স্কেল করা বা দুটিই হতে পারে।
১৬ নম্বর ছবিতে, অ্যাপ্লিকেশনটি ভুল করে ধরে নিয়েছে যে ডিভাইসটি ঘড়ির কাঁটার বিপরীতে ৯০ ডিগ্রি ঘোরানো হয়েছে; এবং তাই, অ্যাপটি একই পরিমাণে প্রিভিউ ঘুরিয়েছে।
১৭ নম্বর ছবিতে, ক্যামেরা প্রিভিউ UI এলিমেন্টের নতুন ডাইমেনশনে ফিট করার জন্য সঠিকভাবে স্কেল করতে, অ্যাপটি ইমেজ বাফারের অ্যাস্পেক্ট রেশিও অ্যাডজাস্ট করেনি।
ফিক্সড-ওরিয়েন্টেশন ক্যামেরা অ্যাপ সাধারণত ফোল্ডেবল এবং ল্যাপটপের মতো অন্যান্য বড় স্ক্রিনের ডিভাইসে সমস্যা সৃষ্টি করে:
ছবি ১৮-এ, ক্যামেরা অ্যাপের UI একপাশে রয়েছে কারণ অ্যাপের ওরিয়েন্টেশন শুধুমাত্র পোর্ট্রেটে সীমাবদ্ধ। ক্যামেরা সেন্সরের সাপেক্ষে ভিউফাইন্ডার ইমেজ সঠিকভাবে ওরিয়েন্টেড।
ইনসেট পোর্ট্রেট মোড
মাল্টি-উইন্ডো মোড কাজ করে না
(resizeableActivity="false") এবং ওরিয়েন্টেশন
সীমাবদ্ধ করে
(screenOrientation="portrait" অথবা
screenOrientation="landscape") এমন ক্যামেরা অ্যাপ
বড় স্ক্রিনের ডিভাইসে ইনসেট পোর্ট্রেট মোডে রাখা যেতে পারে যাতে ক্যামেরার প্রিভিউ
সঠিকভাবে ওরিয়েন্ট করা যায়।
ইনসেট পোর্ট্রেট মোড লেটারবক্স (ইনসেট) পোর্ট্রেট-অনলি অ্যাপকে পোর্ট্রেট ওরিয়েন্টেশনে দেখায়, যদিও ডিসপ্লে অ্যাস্পেক্ট রেশিও ল্যান্ডস্কেপ হয়। ডিসপ্লে অ্যাস্পেক্ট রেশিও পোর্ট্রেট হলেও, শুধুমাত্র ল্যান্ডস্কেপ মোডে কাজ করে এমন অ্যাপ ল্যান্ডস্কেপ ওরিয়েন্টেশনে লেটারবক্স করা হয়। ক্যামেরার ছবি অ্যাপ UI-এর সাথে অ্যালাইন করার জন্য ঘোরানো হয়, ক্যামেরা প্রিভিউয়ের অ্যাস্পেক্ট রেশিওর সাথে ম্যাচ করার জন্য ক্রপ করা হয় এবং তারপর প্রিভিউ পূরণ করার জন্য স্কেল করা হয়।
ক্যামেরা ইমেজ সেন্সরের অ্যাস্পেক্ট রেশিও এবং অ্যাপ্লিকেশনের প্রাথমিক অ্যাক্টিভিটির অ্যাস্পেক্ট রেশিও এক না হলে ইনসেট পোর্ট্রেট মোড ট্রিগার করা হয়।
ছবি ১৯-এ, ল্যাপটপ ডিসপ্লেতে UI সোজা করে দেখানোর জন্য শুধুমাত্র পোর্ট্রেট ক্যামেরা অ্যাপ ঘোরানো হয়েছে। পোর্ট্রেট অ্যাপ ও ল্যান্ডস্কেপ ডিসপ্লের মধ্যে অ্যাস্পেক্ট রেশিওর পার্থক্য থাকার কারণে অ্যাপটি লেটারবক্স করা হয়েছে। অ্যাপের UI রোটেশন (ইনসেট পোর্ট্রেট মোডের কারণে) অ্যাডজাস্ট করার জন্য ক্যামেরা প্রিভিউ ছবি ঘোরানো হয়েছে এবং পোর্ট্রেট ওরিয়েন্টেশনে ফিট করার জন্য ছবি ক্রপ ও স্কেল করা হয়েছে, যার ফলে ফিল্ড অফ ভিউ কমে গেছে।
ঘোরান, ক্রপ করুন, স্কেল করুন
ল্যান্ডস্কেপ অ্যাস্পেক্ট রেশিও আছে এমন ডিসপ্লেতে শুধুমাত্র পোর্ট্রেট ক্যামেরা অ্যাপের জন্য ইনসেট পোর্ট্রেট মোড চালু করা হয়:
অ্যাপটি পোর্ট্রেট ওরিয়েন্টেশনে লেটারবক্স করা হয়েছে:
অ্যাপের রিওরিয়েন্টেশন অ্যাডজাস্ট করার জন্য ক্যামেরার ছবি ৯০ ডিগ্রি ঘোরানো হয়েছে:
ক্যামেরা প্রিভিউয়ের অ্যাস্পেক্ট রেশিও অনুযায়ী ছবি ক্রপ করা হয়, তারপর প্রিভিউ পূরণ করার জন্য স্কেল করা হয় (ফিল্ড অফ ভিউ কমে যায়):
ভাঁজ করা যায় এমন ডিভাইসে, ক্যামেরা সেন্সরের ওরিয়েন্টেশন পোর্ট্রেট হতে পারে যদিও ডিসপ্লের অ্যাস্পেক্ট রেশিও ল্যান্ডস্কেপ:
সেন্সর ওরিয়েন্টেশন অ্যাডজাস্ট করার জন্য ক্যামেরা প্রিভিউ রোটেট করা হয়, তাই ভিউফাইন্ডারে ছবি সঠিকভাবে ওরিয়েন্ট করা থাকে, কিন্তু শুধু পোর্ট্রেট মোডে কাজ করে এমন অ্যাপ পাশাপাশি থাকে।
ইনসেট পোর্ট্রেট মোডে অ্যাপ ও ক্যামেরা প্রিভিউ সঠিকভাবে ওরিয়েন্ট করতে অ্যাপকে শুধু পোর্ট্রেট ওরিয়েন্টেশনে লেটারবক্স করতে হয়:
API
Android 12 (API লেভেল 31) থেকে, অ্যাপগুলি CaptureRequest ক্লাসের SCALER_ROTATE_AND_CROP প্রপার্টির মাধ্যমে ইনসেট পোর্ট্রেট মোড স্পষ্টভাবে নিয়ন্ত্রণ করতে পারে।
ডিফল্ট ভ্যালু হল
SCALER_ROTATE_AND_CROP_AUTO, যা সিস্টেমকে
ইনসেট পোর্ট্রেট মোড চালু করতে দেয়।
SCALER_ROTATE_AND_CROP_90 হল ইনসেট পোর্ট্রেট মোডের
আচরণ, যেমনটি আগে বর্ণনা করা হয়েছে।
সব ডিভাইসে সব SCALER_ROTATE_AND_CROP ভ্যালু কাজ করে না। সাপোর্ট করা ভ্যালুর তালিকা পেতে,
CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES দেখুন।
CameraX
Jetpack CameraX লাইব্রেরি এমন একটি ক্যামেরা ভিউফাইন্ডার তৈরি করে যা সেন্সর ওরিয়েন্টেশন ও ডিভাইস রোটেশনকে একটি সহজ টাস্ক হিসেবে অ্যাকোমোডেট করে।
PreviewView লেআউট এলিমেন্ট ক্যামেরা প্রিভিউ তৈরি করে,
সেন্সর ওরিয়েন্টেশন, ডিভাইস রোটেশন ও স্কেলিংয়ের জন্য অটোমেটিক অ্যাডজাস্ট করে।
PreviewView, FILL_CENTER স্কেল টাইপ প্রয়োগ করে ক্যামেরা ইমেজের অ্যাস্পেক্ট রেশিও বজায় রাখে, যা ইমেজকে কেন্দ্রে নিয়ে আসে কিন্তু
PreviewView-এর ডাইমেনশনের সাথে ম্যাচ করার জন্য এটি ক্রপ করতে পারে। ক্যামেরা ইমেজ লেটারবক্স করতে, স্কেল টাইপ FIT_CENTER-এ সেট করুন।
PreviewView-এর মাধ্যমে ক্যামেরা প্রিভিউ তৈরি করার প্রাথমিক বিষয়গুলি জানতে,
প্রিভিউ প্রয়োগ করুন দেখুন।
সম্পূর্ণ স্যাম্পেল ইমপ্লিমেন্টেশনের জন্য, GitHub-এ
CameraXBasic রিপোজিটরি দেখুন।
CameraViewfinder
প্রিভিউ ব্যবহারের ক্ষেত্রের মতো, CameraViewfinder লাইব্রেরি ক্যামেরা প্রিভিউ তৈরি করার প্রসেসকে সহজ করতে এক সেট টুল প্রদান করে। এটি CameraX Core-এর উপর নির্ভর করে না, তাই আপনি এটিকে আপনার বর্তমান Camera2 কোডবেসে নির্বিঘ্নে ইন্টিগ্রেট করতে পারবেন।
সরাসরি Surface ব্যবহার করার পরিবর্তে, আপনি
Camera2-এর জন্য ক্যামেরা ফিড দেখাতে CameraViewfinder উইজেট ব্যবহার করতে পারেন।
CameraViewfinder ইন্টার্নালি TextureView বা SurfaceView ব্যবহার করে
ক্যামেরা ফিড দেখায় এবং ভিউফাইন্ডার সঠিকভাবে দেখানোর জন্য
প্রয়োজনীয় ট্রান্সফর্মেশন প্রয়োগ করে। এর মধ্যে অ্যাস্পেক্ট রেশিও,
স্কেল ও রোটেশন ঠিক করা অন্তর্ভুক্ত।
CameraViewfinder অবজেক্ট থেকে সারফেসের জন্য অনুরোধ করতে, আপনাকে একটি
ViewfinderSurfaceRequest তৈরি করতে হবে।
এই অনুরোধে CameraCharacteristics থেকে সারফেস রেজোলিউশন এবং ক্যামেরা ডিভাইস সংক্রান্ত তথ্যের প্রয়োজনীয়তা
রয়েছে।
requestSurfaceAsync() কল করলে সারফেস প্রোভাইডারকে অনুরোধ পাঠানো হয়, যা হয় TextureView অথবা SurfaceView এবং Surface-এর ListenableFuture
পাওয়া যায়।
markSurfaceSafeToRelease() কল করলে
সারফেস প্রোভাইডারকে জানানো হয় যে সারফেসের প্রয়োজন নেই এবং সম্পর্কিত রিসোর্স
রিলিজ করা যেতে পারে।
fun startCamera() {
val previewResolution = Size(width, height)
val viewfinderSurfaceRequest =
ViewfinderSurfaceRequest(previewResolution, characteristics)
val surfaceListenableFuture =
cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest)
Futures.addCallback(surfaceListenableFuture, object : FutureCallback<Surface> {
override fun onSuccess(surface: Surface) {
/* create a CaptureSession using this surface as usual */
}
override fun onFailure(t: Throwable) { /* something went wrong */ }
}, ContextCompat.getMainExecutor(context))
}
SurfaceView
প্রিভিউতে প্রসেসিংয়ের প্রয়োজন না হলে এবং সেটি অ্যানিমেটেড না হলে,
ক্যামেরা প্রিভিউ তৈরি করার জন্য SurfaceView হল একটি সহজ পদ্ধতি।
SurfaceView ডিসপ্লে ওরিয়েন্টেশনের সাথে ম্যাচ করার জন্য ক্যামেরা সেন্সর ইমেজ বাফার অটোমেটিক রোটেট করে,
সেন্সর ওরিয়েন্টেশন ও ডিভাইস রোটেশন, দুটিরই হিসেব রাখে।
তবে, ছবির বাফারকে SurfaceView ডাইমেনশনে ফিট করার জন্য স্কেল করা হয়,
অ্যাস্পেক্ট রেশিও বিবেচনা করা হয় না।
আপনাকে অবশ্যই নিশ্চিত করতে হবে যে ইমেজ বাফারের অ্যাসপেক্ট রেশিও SurfaceView-এর অ্যাসপেক্ট রেশিওর সাথে মেলে, যা আপনি কম্পোনেন্টের onMeasure() পদ্ধতিতে SurfaceView-এর কন্টেন্ট স্কেল করে করতে পারেন:
(computeRelativeRotation() সোর্স কোড
নিচে আপেক্ষিক রোটেশন-এ আছে।)
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { val width = MeasureSpec.getSize(widthMeasureSpec) val height = MeasureSpec.getSize(heightMeasureSpec) val relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees) if (previewWidth > 0f && previewHeight > 0f) { /* Scale factor required to scale the preview to its original size on the x-axis. */ val scaleX = if (relativeRotation % 180 == 0) { width.toFloat() / previewWidth } else { width.toFloat() / previewHeight } /* Scale factor required to scale the preview to its original size on the y-axis. */ val scaleY = if (relativeRotation % 180 == 0) { height.toFloat() / previewHeight } else { height.toFloat() / previewWidth } /* Scale factor required to fit the preview to the SurfaceView size. */ val finalScale = min(scaleX, scaleY) setScaleX(1 / scaleX * finalScale) setScaleY(1 / scaleY * finalScale) } setMeasuredDimension(width, height) }
ক্যামেরা প্রিভিউ হিসেবে SurfaceView প্রয়োগ করার ব্যাপারে আরও জানতে,
ক্যামেরা ওরিয়েন্টেশন দেখুন।
TextureView
SurfaceView-এর তুলনায় TextureView-এর পারফর্ম্যান্স কম—এবং
আরও কাজ—তবে TextureView আপনাকে ক্যামেরা প্রিভিউয়ের সর্বাধিক নিয়ন্ত্রণ
দেয়।
TextureView সেন্সর ওরিয়েন্টেশনের ভিত্তিতে সেন্সর ইমেজ বাফার রোটেট করে, কিন্তু
ডিভাইস রোটেশন বা প্রিভিউ স্কেলিং ম্যানেজ করে না।
স্কেলিং ও রোটেশন ম্যাট্রিক্স ট্রান্সফর্মেশনে এনকোড করা যেতে পারে।
TextureView কীভাবে সঠিকভাবে স্কেল ও রোটেট করতে হয় তা জানতে, আপনার ক্যামেরা অ্যাপে
রিসাইজ করা যায় এমন সারফেসের জন্য সহায়তা দেখুন।
আপেক্ষিক রোটেশন
ক্যামেরা সেন্সরের আপেক্ষিক রোটেশন হল ক্যামেরা সেন্সর আউটপুটকে ডিভাইসের ওরিয়েন্টেশনের সাথে অ্যালাইন করার জন্য প্রয়োজনীয় রোটেশনের পরিমাণ।
প্রিভিউ ইমেজের জন্য x ও y স্কেলিং ফ্যাক্টর নির্ধারণ করতে
SurfaceView ও TextureView-এর মতো কম্পোনেন্ট আপেক্ষিক রোটেশন ব্যবহার করে। এছাড়াও, এটি সেন্সর ইমেজ বাফারের রোটেশন নির্দিষ্ট করতে
ব্যবহার করা হয়।
CameraCharacteristics এবং Surface
ক্লাস ক্যামেরা সেন্সরের আপেক্ষিক রোটেশন গণনা করতে সাহায্য করে:
/** * Computes rotation required to transform the camera sensor output orientation to the * device's current orientation in degrees. * * @param characteristics The CameraCharacteristics to query for the sensor orientation. * @param surfaceRotationDegrees The current device orientation as a Surface constant. * @return Relative rotation of the camera sensor output. */ public fun computeRelativeRotation( characteristics: CameraCharacteristics, surfaceRotationDegrees: Int ): Int { val sensorOrientationDegrees = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION) ?: 0 // Reverse device orientation for back-facing cameras. val sign = if (characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT ) 1 else -1 // Calculate desired orientation relative to camera orientation to make // the image upright relative to the device orientation. return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360 }
উইন্ডো মেট্রিক
ক্যামেরা ভিউফাইন্ডারের ডাইমেনশন নির্ধারণ করার জন্য স্ক্রিনের সাইজ ব্যবহার করা উচিত নয়; ক্যামেরা অ্যাপ স্ক্রিনের কোনও অংশে, মোবাইল ডিভাইসে মাল্টি-উইন্ডো মোডে অথবা ChromeOS-এ ফ্রি-ফর্ম মোডে চলতে পারে।
WindowManager#getCurrentWindowMetrics()
(API লেভেল ৩০-এ যোগ করা হয়েছে) স্ক্রিনের সাইজের পরিবর্তে অ্যাপ্লিকেশন উইন্ডোর সাইজ
রিটার্ন করে। Jetpack WindowManager লাইব্রেরি পদ্ধতি
WindowMetricsCalculator#computeCurrentWindowMetrics()
এবং WindowInfoTracker#currentWindowMetrics()
API লেভেল ১৪-এ ব্যাকওয়ার্ড কম্প্যাটিবিলিটির সাথে একই ধরনের সহায়তা প্রদান করে।
১৮০ ডিগ্রিতে ঘোরানো
ডিভাইস ১৮০ ডিগ্রি ঘোরানো হলে (যেমন, স্বাভাবিক ওরিয়েন্টেশন থেকে
স্বাভাবিক ওরিয়েন্টেশন উল্টো করে দেওয়া)
onConfigurationChanged() কলব্যাক ট্রিগার হয় না। এর ফলে, ক্যামেরা প্রিভিউ উল্টো হয়ে যেতে পারে।
১৮০ ডিগ্রি রোটেশন শনাক্ত করতে,
DisplayListener প্রয়োগ করুন এবং
onDisplayChanged() কলব্যাকে Display#getRotation()-এ
কল করে ডিভাইসের রোটেশন চেক করুন।
এক্সক্লুসিভ রিসোর্স
Android 10-এর আগে, মাল্টি-উইন্ডো এনভায়রনমেন্টে শুধুমাত্র সবচেয়ে উপরে দেখা যাওয়া অ্যাক্টিভিটি
RESUMED স্ট্যাটাসে থাকত। এটি ব্যবহারকারীদের জন্য বিভ্রান্তিকর ছিল কারণ
সিস্টেমটি কোন অ্যাক্টিভিটি আবার শুরু করা হয়েছে তার কোনও ইঙ্গিত দেয়নি।
Android 10 (API লেভেল ২৯) মাল্টি-রিজিউম চালু করেছে যেখানে সব দৃশ্যমান অ্যাক্টিভিটি
RESUMED স্টেটে থাকে। দৃশ্যমান অ্যাক্টিভিটি এখনও PAUSED
স্টেটে প্রবেশ করতে পারে, যেমন, কোনও স্বচ্ছ অ্যাক্টিভিটি যদি অ্যাক্টিভিটির উপরে থাকে বা
অ্যাক্টিভিটি ফোকাস করা না যায়, যেমন ছবির-মধ্যে-ছবি মোডে (ছবির-মধ্যে-ছবি সংক্রান্ত সহায়তা
দেখুন)।
API লেভেল ২৯ বা তার পরবর্তী যেকোনও ভার্সনে ক্যামেরা, মাইক্রোফোন বা যেকোনও এক্সক্লুসিভ বা সিঙ্গলটন
রিসোর্স ব্যবহার করা অ্যাপ্লিকেশনকে অবশ্যই মাল্টি-রিজিউম সাপোর্ট করতে হবে। যেমন, তিনটি
আবার শুরু করা অ্যাক্টিভিটি যদি ক্যামেরা ব্যবহার করতে চায়, তাহলে শুধুমাত্র একটি অ্যাক্টিভিটি এই
এক্সক্লুসিভ রিসোর্স অ্যাক্সেস করতে পারবে। আরও বেশি অগ্রাধিকারপ্রাপ্ত অ্যাক্টিভিটির মাধ্যমে ক্যামেরার প্রি-এমপ্টিভ অ্যাক্সেস সম্পর্কে সচেতন থাকতে,
প্রতিটি অ্যাক্টিভিটিকে অবশ্যই একটি
onDisconnected() কলব্যাক প্রয়োগ করতে হবে।
আরও তথ্যের জন্য, মাল্টি-রিজিউম দেখুন।
অতিরিক্ত রিসোর্স
- Camera2 স্যাম্পেলের জন্য, GitHub-এ Camera2Basic অ্যাপ দেখুন।
- CameraX প্রিভিউ ব্যবহারের কেস সম্পর্কে জানতে, CameraX প্রিভিউ প্রয়োগ করুন দেখুন।
- CameraX ক্যামেরা প্রিভিউ স্যাম্পেল ইমপ্লিমেন্টেশনের জন্য, GitHub-এ CameraXBasic রিপোজিটরি দেখুন।
- ChromeOS-এ ক্যামেরা প্রিভিউ সম্পর্কে তথ্যের জন্য, ক্যামেরা ওরিয়েন্টেশন দেখুন।
- ফোল্ডেবল ডিভাইসের জন্য ডেভেলপ করা সম্পর্কে তথ্য পেতে, ফোল্ডেবল সম্পর্কে জানুন।