গাড়ির ক্যামেরা HAL

অ্যান্ড্রয়েডে একটি অটোমোটিভ HIDL হার্ডওয়্যার অ্যাবস্ট্রাকশন লেয়ার (HAL) রয়েছে, যা অ্যান্ড্রয়েড বুট প্রক্রিয়ার একেবারে শুরুতে ছবি তোলা ও প্রদর্শনের ব্যবস্থা করে এবং সিস্টেমের পুরো জীবনকাল ধরে কাজ করতে থাকে। HAL-এর মধ্যে এক্সটেরিয়র ভিউ সিস্টেম (EVS) স্ট্যাক অন্তর্ভুক্ত এবং এটি সাধারণত অ্যান্ড্রয়েড-ভিত্তিক ইন-ভেহিকেল ইনফোটেইনমেন্ট (IVI) সিস্টেমযুক্ত যানবাহনে রিয়ারভিউ ক্যামেরা ও সারাউন্ড ভিউ ডিসপ্লে সমর্থন করতে ব্যবহৃত হয়। EVS ব্যবহারকারীর অ্যাপে উন্নত ফিচারগুলো বাস্তবায়নের সুযোগও করে দেয়।

অ্যান্ড্রয়েডে একটি EVS-নির্দিষ্ট ক্যাপচার এবং ডিসপ্লে ড্রাইভার ইন্টারফেসও অন্তর্ভুক্ত রয়েছে (যা /hardware/interfaces/automotive/evs/1.0 এ অবস্থিত)। যদিও বিদ্যমান অ্যান্ড্রয়েড ক্যামেরা এবং ডিসপ্লে পরিষেবাগুলোর উপর ভিত্তি করে একটি রিয়ারভিউ ক্যামেরা অ্যাপ তৈরি করা সম্ভব, তবে এই ধরনের অ্যাপ সম্ভবত অ্যান্ড্রয়েড বুট প্রক্রিয়ায় অনেক দেরিতে চালু হবে। একটি ডেডিকেটেড HAL ব্যবহার করলে একটি সুবিন্যস্ত ইন্টারফেস পাওয়া যায় এবং এটি স্পষ্ট করে দেয় যে EVS স্ট্যাককে সমর্থন করার জন্য একটি OEM-কে কী বাস্তবায়ন করতে হবে।

সিস্টেমের উপাদানসমূহ

EVS-এ নিম্নলিখিত সিস্টেম উপাদানগুলো অন্তর্ভুক্ত রয়েছে:

ইভিএস সিস্টেম উপাদানের ডায়াগ্রাম
চিত্র ১. ইভিএস সিস্টেমের উপাদানসমূহের সংক্ষিপ্ত বিবরণ।

ইভিএস অ্যাপ

একটি নমুনা C++ EVS অ্যাপ ( /packages/services/Car/evs/app ) একটি রেফারেন্স ইমপ্লিমেন্টেশন হিসেবে কাজ করে। এই অ্যাপটি EVS ম্যানেজারের কাছ থেকে ভিডিও ফ্রেমের জন্য অনুরোধ করে এবং প্রদর্শনের জন্য প্রস্তুত ফ্রেমগুলি আবার EVS ম্যানেজারের কাছে ফেরত পাঠায়। EVS এবং কার সার্ভিস উপলব্ধ হওয়ার সাথে সাথেই, পাওয়ার অন করার দুই (2) সেকেন্ডের মধ্যে, init দ্বারা এটি চালু হবে বলে আশা করা হয়। OEM-রা তাদের ইচ্ছামত EVS অ্যাপটি পরিবর্তন বা প্রতিস্থাপন করতে পারেন।

ইভিএস ম্যানেজার

ইভিএস ম্যানেজার ( /packages/services/Car/evs/manager ) একটি ইভিএস অ্যাপের জন্য প্রয়োজনীয় উপাদান সরবরাহ করে, যা দিয়ে একটি সাধারণ রিয়ারভিউ ক্যামেরা ডিসপ্লে থেকে শুরু করে ৬ডিওএফ মাল্টি-ক্যামেরা রেন্ডারিং পর্যন্ত যেকোনো কিছু বাস্তবায়ন করা যায়। এর ইন্টারফেসটি এইচআইডিএল (HIDL)-এর মাধ্যমে উপস্থাপিত হয় এবং এটি একই সাথে একাধিক ক্লায়েন্টকে গ্রহণ করার জন্য তৈরি। অন্যান্য অ্যাপ এবং সার্ভিস (বিশেষ করে কার সার্ভিস) ইভিএস সিস্টেমটি কখন সক্রিয় আছে তা জানার জন্য ইভিএস ম্যানেজারের স্টেট কোয়েরি করতে পারে।

EVS HIDL ইন্টারফেস

EVS সিস্টেম, যার মধ্যে ক্যামেরা এবং ডিসপ্লে উভয় উপাদানই রয়েছে, তা android.hardware.automotive.evs প্যাকেজে সংজ্ঞায়িত করা আছে। একটি নমুনা ইমপ্লিমেন্টেশন, যা ইন্টারফেসটির কার্যকারিতা পরীক্ষা করে (কৃত্রিম পরীক্ষার ছবি তৈরি করে এবং ছবিগুলো সম্পূর্ণ ফিরে আসে কিনা তা যাচাই করে), তা /hardware/interfaces/automotive/evs/1.0/default -এ প্রদান করা হয়েছে।

OEM /hardware/interfaces/automotive/evs এ থাকা .hal ফাইলগুলিতে প্রকাশিত API বাস্তবায়নের জন্য দায়ী। এই ধরনের বাস্তবায়নগুলি ফিজিক্যাল ক্যামেরা থেকে ডেটা কনফিগার ও সংগ্রহ করে এবং Gralloc দ্বারা শনাক্তযোগ্য শেয়ার্ড মেমরি বাফারের মাধ্যমে তা সরবরাহ করে। বাস্তবায়নের ডিসপ্লে অংশটি একটি শেয়ার্ড মেমরি বাফার সরবরাহ করার জন্য দায়ী, যা অ্যাপ দ্বারা পূরণ করা যেতে পারে (সাধারণত EGL রেন্ডারিংয়ের মাধ্যমে) এবং ফিজিক্যাল ডিসপ্লেতে প্রদর্শিত হতে চাওয়া অন্য যেকোনো কিছুর চেয়ে সমাপ্ত ফ্রেমগুলিকে অগ্রাধিকার দিয়ে উপস্থাপন করে। EVS ইন্টারফেসের ভেন্ডর বাস্তবায়নগুলি /vendor/… /device/… বা hardware/… এর অধীনে সংরক্ষিত থাকতে পারে (যেমন, /hardware/[vendor]/[platform]/evs )।

কার্নেল ড্রাইভার

যে ডিভাইস EVS স্ট্যাক সমর্থন করে, তার জন্য কার্নেল ড্রাইভার প্রয়োজন। নতুন ড্রাইভার তৈরি করার পরিবর্তে, OEM-দের কাছে বিদ্যমান ক্যামেরা বা ডিসপ্লে হার্ডওয়্যার ড্রাইভারের মাধ্যমে EVS-এর জন্য প্রয়োজনীয় ফিচারগুলো সমর্থন করার বিকল্প রয়েছে। ড্রাইভার পুনঃব্যবহার করা সুবিধাজনক হতে পারে, বিশেষ করে ডিসপ্লে ড্রাইভারের ক্ষেত্রে, যেখানে ছবি প্রদর্শনের জন্য অন্যান্য সক্রিয় থ্রেডের সাথে সমন্বয়ের প্রয়োজন হতে পারে। অ্যান্ড্রয়েড ৮.০-তে একটি v4l2-ভিত্তিক স্যাম্পল ড্রাইভার ( packages/services/Car/evs/sampleDriver ) অন্তর্ভুক্ত রয়েছে, যা v4l2 সমর্থনের জন্য কার্নেলের উপর এবং আউটপুট ছবি প্রদর্শনের জন্য SurfaceFlinger-এর উপর নির্ভরশীল।

EVS হার্ডওয়্যার ইন্টারফেসের বর্ণনা

এই অংশে HAL সম্পর্কে বর্ণনা করা হয়েছে। বিক্রেতাদের তাদের হার্ডওয়্যারের জন্য অভিযোজিত এই API-এর বাস্তবায়ন সরবরাহ করতে হবে।

IEvsEnumerator

এই অবজেক্টটি সিস্টেমে উপলব্ধ EVS হার্ডওয়্যার (এক বা একাধিক ক্যামেরা এবং একক ডিসপ্লে ডিভাইস) গণনা করার জন্য দায়ী।

getCameraList() generates (vec<CameraDesc> cameras);

সিস্টেমের সমস্ত ক্যামেরার বিবরণ সম্বলিত একটি ভেক্টর ফেরত দেয়। ধরে নেওয়া হয় যে ক্যামেরার সেটটি স্থির এবং বুট করার সময় তা জানা সম্ভব। ক্যামেরার বিবরণ সম্পর্কে বিস্তারিত জানতে CameraDesc দেখুন।

openCamera(string camera_id) generates (IEvsCamera camera);

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

closeCamera(IEvsCamera camera);

IEvsCamera ইন্টারফেসটি রিলিজ করে (এবং এটি openCamera() কলের বিপরীত)। closeCamera কল করার আগে stopVideoStream() কল করে ক্যামেরা ভিডিও স্ট্রিমটি অবশ্যই বন্ধ করতে হবে।

openDisplay() generates (IEvsDisplay display);

সিস্টেমের EVS ডিসপ্লের সাথে একচেটিয়াভাবে ইন্টারঅ্যাক্ট করার জন্য ব্যবহৃত একটি ইন্টারফেস অবজেক্ট অর্জন করে। একবারে শুধুমাত্র একটি ক্লায়েন্ট IEvsDisplay-এর একটি কার্যকরী ইনস্ট্যান্স ধারণ করতে পারে। openCamera তে বর্ণিত আগ্রাসী ওপেন আচরণের মতোই, যেকোনো সময় একটি নতুন IEvsDisplay অবজেক্ট তৈরি করা যেতে পারে এবং এটি পূর্ববর্তী যেকোনো ইনস্ট্যান্সকে নিষ্ক্রিয় করে দেয়। নিষ্ক্রিয় ইনস্ট্যান্সগুলো বিদ্যমান থাকে এবং তাদের মালিকদের ফাংশন কলে সাড়া দেয়, কিন্তু নিষ্ক্রিয় অবস্থায় কোনো মিউটেটিং অপারেশন সম্পাদন করতে পারে না। অবশেষে, ক্লায়েন্ট অ্যাপটি OWNERSHIP_LOST এরর রিটার্ন কোডগুলো লক্ষ্য করবে এবং নিষ্ক্রিয় ইন্টারফেসটি বন্ধ ও রিলিজ করবে বলে আশা করা হয়।

closeDisplay(IEvsDisplay display);

IEvsDisplay ইন্টারফেসটি রিলিজ করে (এবং এটি openDisplay() কলের বিপরীত)। getTargetBuffer() কলের মাধ্যমে প্রাপ্ত বকেয়া বাফারগুলো ডিসপ্লে বন্ধ করার আগে অবশ্যই ডিসপ্লেতে ফেরত দিতে হবে।

getDisplayState() generates (DisplayState state);

বর্তমান ডিসপ্লে অবস্থাটি পাওয়া যায়। HAL ইমপ্লিমেন্টেশনের উচিত প্রকৃত বর্তমান অবস্থাটি রিপোর্ট করা, যা সর্বশেষ অনুরোধ করা অবস্থা থেকে ভিন্ন হতে পারে। ডিসপ্লে অবস্থা পরিবর্তনের জন্য দায়ী লজিকটি ডিভাইস লেয়ারের উপরে থাকা উচিত, যার ফলে HAL ইমপ্লিমেন্টেশনের পক্ষে স্বতঃস্ফূর্তভাবে ডিসপ্লে অবস্থা পরিবর্তন করা অনাকাঙ্ক্ষিত। যদি ডিসপ্লেটি বর্তমানে কোনো ক্লায়েন্ট দ্বারা ধারণ করা না থাকে (openDisplay কলের মাধ্যমে), তাহলে এই ফাংশনটি NOT_OPEN রিটার্ন করে। অন্যথায়, এটি EVS ডিসপ্লের বর্তমান অবস্থা রিপোর্ট করে ( IEvsDisplay API দেখুন)।

struct CameraDesc {
    string      camera_id;
    int32       vendor_flags;       // Opaque value
}
  • camera_id . একটি স্ট্রিং যা একটি নির্দিষ্ট ক্যামেরাকে অনন্যভাবে শনাক্ত করে। এটি ডিভাইসটির কার্নেল ডিভাইসের নাম অথবা ডিভাইসটির একটি নাম, যেমন rearview , হতে পারে। এই স্ট্রিংটির মান HAL ইমপ্লিমেন্টেশন দ্বারা নির্বাচিত হয় এবং এর উপরের স্ট্যাক দ্বারা অস্বচ্ছভাবে ব্যবহৃত হয়।
  • vendor_flags . ড্রাইভার থেকে একটি কাস্টম EVS অ্যাপে বিশেষায়িত ক্যামেরা তথ্য অস্বচ্ছভাবে পাঠানোর একটি পদ্ধতি। এই তথ্য ড্রাইভার থেকে EVS অ্যাপে কোনো ব্যাখ্যা ছাড়াই পাঠানো হয়, এবং অ্যাপটি চাইলে তা উপেক্ষা করতে পারে।

আইইভিএসক্যামেরা

এই অবজেক্টটি একটি একক ক্যামেরাকে প্রতিনিধিত্ব করে এবং এটি ছবি তোলার প্রধান ইন্টারফেস।

getCameraInfo() generates (CameraDesc info);

এই ক্যামেরার CameraDesc ফেরত দেয়।

setMaxFramesInFlight(int32 bufferCount) generates (EvsResult result);

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

অনুরোধকৃত bufferCount ধারণ করা সম্ভব না হলে, ফাংশনটি BUFFER_NOT_AVAILABLE বা অন্য কোনো প্রাসঙ্গিক ত্রুটি কোড রিটার্ন করে। এক্ষেত্রে, সিস্টেমটি পূর্বে সেট করা মান নিয়েই কাজ চালিয়ে যায়।

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

এই ক্যামেরা থেকে EVS ক্যামেরা ফ্রেম সরবরাহের জন্য অনুরোধ করা হচ্ছে। stopVideoStream() কল না করা পর্যন্ত IEvsCameraStream পর্যায়ক্রমিকভাবে নতুন ইমেজ ফ্রেম গ্রহণ করতে থাকে। startVideoStream কল করার ৫০০ মিলিসেকেন্ডের মধ্যে ফ্রেম সরবরাহ শুরু করতে হবে এবং শুরু হওয়ার পর, তা অবশ্যই ন্যূনতম ১০ FPS হারে তৈরি করতে হবে। ভিডিও স্ট্রিম শুরু করার জন্য প্রয়োজনীয় সময় কার্যকরভাবে যেকোনো রিয়ারভিউ ক্যামেরা চালু হওয়ার প্রয়োজনীয় সময়ের মধ্যে গণনা করা হয়। যদি স্ট্রিমটি শুরু না হয়, তবে একটি এরর কোড অবশ্যই ফেরত দিতে হবে; অন্যথায় OK ফেরত দেওয়া হয়।

oneway doneWithFrame(BufferDesc buffer);

IEvsCameraStream-এ পাঠানো একটি ফ্রেম ফেরত দেয়। IEvsCameraStream ইন্টারফেসে পাঠানো একটি ফ্রেম ব্যবহার করা হয়ে গেলে, সেটিকে পুনরায় ব্যবহারের জন্য অবশ্যই IEvsCamera-তে ফেরত দিতে হবে। অল্প সংখ্যক, সসীম বাফার উপলব্ধ থাকে (সম্ভবত সর্বনিম্ন একটি), এবং যদি বাফারের সরবরাহ শেষ হয়ে যায়, তাহলে একটি বাফার ফেরত না দেওয়া পর্যন্ত আর কোনো ফ্রেম পাঠানো হয় না, যার ফলে কিছু ফ্রেম বাদ পড়ে যেতে পারে (একটি নাল হ্যান্ডেলযুক্ত বাফার একটি স্ট্রিমের সমাপ্তি নির্দেশ করে এবং এই ফাংশনের মাধ্যমে সেটি ফেরত দেওয়ার প্রয়োজন নেই)। সফল হলে OK ফেরত দেয়, অথবা উপযুক্ত এরর কোড ফেরত দেয়, যার মধ্যে INVALID_ARG বা BUFFER_NOT_AVAILABLE অন্তর্ভুক্ত থাকতে পারে।

stopVideoStream();

EVS ক্যামেরা ফ্রেমের ডেলিভারি বন্ধ করে দেয়। যেহেতু ডেলিভারি অ্যাসিঙ্ক্রোনাস, তাই এই কলটি রিটার্ন করার পরেও কিছু সময়ের জন্য ফ্রেম আসতে পারে। IEvsCameraStream-কে স্ট্রিমটি বন্ধ করার সংকেত না দেওয়া পর্যন্ত প্রতিটি ফ্রেম অবশ্যই রিটার্ন করতে হবে। যে স্ট্রিমটি ইতিমধ্যেই বন্ধ করা হয়েছে বা কখনও শুরুই হয়নি, সেটিতে stopVideoStream কল করা বৈধ; তবে সেক্ষেত্রে এটি উপেক্ষা করা হয়।

getExtendedInfo(int32 opaqueIdentifier) generates (int32 value);

HAL ইমপ্লিমেন্টেশন থেকে ড্রাইভার-নির্দিষ্ট তথ্যের জন্য অনুরোধ করা হয়। opaqueIdentifier এর জন্য অনুমোদিত মানগুলো ড্রাইভার-নির্দিষ্ট, কিন্তু কোনো মান পাস না করলে ড্রাইভারটি ক্র্যাশ করতে পারে। যেকোনো অচেনা opaqueIdentifier জন্য ড্রাইভারের ০ রিটার্ন করা উচিত।

setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);

HAL ইমপ্লিমেন্টেশনে একটি ড্রাইভার-নির্দিষ্ট মান পাঠায়। এই এক্সটেনশনটি শুধুমাত্র যানবাহন-নির্দিষ্ট এক্সটেনশনগুলিকে সহজতর করার জন্য প্রদান করা হয়েছে এবং ডিফল্ট অবস্থায় কাজ করার জন্য কোনো HAL ইমপ্লিমেন্টেশনের এই কলটির প্রয়োজন হওয়া উচিত নয়। যদি ড্রাইভার মানগুলি চিনতে ও গ্রহণ করতে পারে, তাহলে OK ফেরত দেওয়া উচিত; অন্যথায় INVALID_ARG বা অন্য কোনো প্রতিনিধিত্বমূলক ত্রুটি কোড ফেরত দেওয়া উচিত।

struct BufferDesc {
    uint32  width;      // Units of pixels
    uint32  height;     // Units of pixels
    uint32  stride;     // Units of pixels
    uint32  pixelSize;  // Size of single pixel in bytes
    uint32  format;     // May contain values from android_pixel_format_t
    uint32  usage;      // May contain values from Gralloc.h
    uint32  bufferId;   // Opaque value
    handle  memHandle;  // gralloc memory buffer handle
}

এপিআই (API)-এর মাধ্যমে প্রেরিত একটি ইমেজের বর্ণনা দেয়। ইমেজ বাফারটির বর্ণনা দেওয়ার জন্য এই স্ট্রাকচারটি পূরণ করার দায়িত্ব এইচএএল (HAL) ড্রাইভের এবং এইচএএল ক্লায়েন্টের এই স্ট্রাকচারটিকে শুধুমাত্র পঠনযোগ্য (read-only) হিসেবে বিবেচনা করা উচিত। ফিল্ডগুলোতে ক্লায়েন্টকে একটি ANativeWindowBuffer অবজেক্ট পুনর্গঠন করার জন্য যথেষ্ট তথ্য থাকে, যা eglCreateImageKHR() এক্সটেনশনসহ ইজিএল (EGL)-এর সাথে ইমেজটি ব্যবহার করার জন্য প্রয়োজন হতে পারে।

  • width । প্রদর্শিত ছবিটির প্রস্থ, পিক্সেল এককে।
  • height । প্রদর্শিত ছবিটির উচ্চতা, পিক্সেল এককে।
  • stride . সারিগুলোর অ্যালাইনমেন্টের জন্য ব্যবহৃত প্যাডিং সহ, প্রতিটি সারি মেমোরিতে প্রকৃতপক্ষে যত পিক্সেল জায়গা নেয়। গ্র্যালক (gralloc) তার বাফার বর্ণনার জন্য যে রীতি গ্রহণ করেছে, তার সাথে মিল রেখে এটিকে পিক্সেলে প্রকাশ করা হয়।
  • pixelSize . প্রতিটি স্বতন্ত্র পিক্সেল দ্বারা দখলকৃত বাইটের সংখ্যা, যা ছবির সারিগুলির মধ্যে এক সারি থেকে অন্য সারিতে যাওয়ার জন্য প্রয়োজনীয় বাইটের আকার গণনা করতে সক্ষম করে (বাইটে stride = পিক্সেলে stride * pixelSize )।
  • format । ছবিতে ব্যবহৃত পিক্সেল ফরম্যাট। প্রদত্ত ফরম্যাটটি অবশ্যই প্ল্যাটফর্মের OpenGL ইমপ্লিমেন্টেশনের সাথে সামঞ্জস্যপূর্ণ হতে হবে। সামঞ্জস্যতা পরীক্ষায় উত্তীর্ণ হওয়ার জন্য, ক্যামেরায় ব্যবহারের ক্ষেত্রে HAL_PIXEL_FORMAT_YCRCB_420_SP এবং প্রদর্শনের জন্য RGBA বা BGRA অগ্রাধিকার দেওয়া উচিত।
  • usage । HAL ইমপ্লিমেন্টেশন দ্বারা নির্ধারিত ব্যবহার ফ্ল্যাগ। HAL ক্লায়েন্টদের এগুলি অপরিবর্তিতভাবে পাস করতে হবে (বিস্তারিত জানতে Gralloc.h এর সম্পর্কিত ফ্ল্যাগগুলি দেখুন)।
  • bufferId . HAL API-গুলোর মধ্য দিয়ে একবার ঘুরে আসার পর একটি বাফারকে শনাক্ত করার জন্য HAL ইমপ্লিমেন্টেশন দ্বারা নির্দিষ্ট করা একটি অনন্য মান। এই ফিল্ডে সংরক্ষিত মানটি HAL ইমপ্লিমেন্টেশন দ্বারা যথেচ্ছভাবে বেছে নেওয়া যেতে পারে।
  • memHandle . যে অন্তর্নিহিত মেমরি বাফারে ছবির ডেটা থাকে, তার হ্যান্ডেল। HAL ইমপ্লিমেন্টেশন এখানে একটি Gralloc বাফার হ্যান্ডেল সংরক্ষণ করতে পারে।

আইইভিএসক্যামেরাস্ট্রিম

ক্লায়েন্ট অ্যাসিঙ্ক্রোনাস ভিডিও ফ্রেম ডেলিভারি গ্রহণ করার জন্য এই ইন্টারফেসটি প্রয়োগ করে।

deliverFrame(BufferDesc buffer);

যখনই কোনো ভিডিও ফ্রেম পরিদর্শনের জন্য প্রস্তুত হয়, তখন এটি HAL থেকে কল গ্রহণ করে। এই পদ্ধতির মাধ্যমে প্রাপ্ত বাফার হ্যান্ডেলগুলি অবশ্যই IEvsCamera::doneWithFrame() কলের মাধ্যমে ফেরত দিতে হবে। যখন IEvsCamera::stopVideoStream() কল করে ভিডিও স্ট্রিম বন্ধ করা হয়, তখন পাইপলাইনটি নিষ্কাশিত হওয়ার সাথে সাথে এই কলব্যাকটি চলতে পারে। প্রতিটি ফ্রেম অবশ্যই ফেরত দিতে হবে; যখন স্ট্রিমের শেষ ফ্রেমটি সরবরাহ করা হয়ে যায়, তখন একটি NULL bufferHandle সরবরাহ করা হয়, যা স্ট্রিমের সমাপ্তি নির্দেশ করে এবং এরপর আর কোনো ফ্রেম সরবরাহ করা হয় না। NULL bufferHandle নিজে doneWithFrame() এর সাথে ফেরত পাঠানোর প্রয়োজন নেই, কিন্তু অন্য সমস্ত হ্যান্ডেল অবশ্যই ফেরত দিতে হবে।

যদিও প্রোপ্রাইটারি বাফার ফরম্যাট প্রযুক্তিগতভাবে সম্ভব, সামঞ্জস্যতা পরীক্ষার জন্য বাফারটিকে চারটি সমর্থিত ফরম্যাটের মধ্যে একটিতে থাকতে হবে: NV21 (YCrCb 4:2:0 সেমি-প্ল্যানার), YV12 (YCrCb 4:2:0 প্ল্যানার), YUYV (YCrCb 4:2:2 ইন্টারলিভড), RGBA (৩২ বিট R:G:B:x), BGRA (৩২ বিট B:G:R:x)। নির্বাচিত ফরম্যাটটি অবশ্যই প্ল্যাটফর্মের GLES ইমপ্লিমেন্টেশনে একটি বৈধ GL টেক্সচার সোর্স হতে হবে।

অ্যাপটির BufferDesc স্ট্রাকচারের bufferId ফিল্ড এবং memHandle মধ্যেকার কোনো সামঞ্জস্যের উপর নির্ভর করা উচিত নয়bufferId মানগুলো মূলত HAL ড্রাইভার ইমপ্লিমেন্টেশনের নিজস্ব, এবং এটি নিজের প্রয়োজন অনুযায়ী সেগুলো ব্যবহার (এবং পুনঃব্যবহার) করতে পারে।

আইইভিএসডিসপ্লে

এই অবজেক্টটি Evs ডিসপ্লেকে প্রতিনিধিত্ব করে, ডিসপ্লের অবস্থা নিয়ন্ত্রণ করে এবং ছবিগুলোর প্রকৃত উপস্থাপনা পরিচালনা করে।

getDisplayInfo() generates (DisplayDesc info);

সিস্টেম দ্বারা প্রদত্ত EVS ডিসপ্লে সম্পর্কে প্রাথমিক তথ্য ফেরত দেয় (দেখুন DisplayDesc )।

setDisplayState(DisplayState state) generates (EvsResult result);

ডিসপ্লে স্টেট নির্ধারণ করে। ক্লায়েন্টরা তাদের কাঙ্ক্ষিত অবস্থা প্রকাশ করার জন্য ডিসপ্লে স্টেট নির্ধারণ করতে পারে, এবং HAL ইমপ্লিমেন্টেশনকে অন্য যেকোনো স্টেটে থাকা অবস্থায় যেকোনো স্টেটের জন্য করা অনুরোধ সুষ্ঠুভাবে গ্রহণ করতে হবে, যদিও এর প্রতিক্রিয়া হিসেবে অনুরোধটি উপেক্ষা করাও হতে পারে।

প্রারম্ভিকীকরণের সময়, ডিসপ্লেটি NOT_VISIBLE অবস্থায় শুরু হওয়ার জন্য নির্ধারিত থাকে, যার পরে ক্লায়েন্ট VISIBLE_ON_NEXT_FRAME অবস্থার জন্য অনুরোধ করবে এবং ভিডিও সরবরাহ করা শুরু করবে। যখন ডিসপ্লেটির আর প্রয়োজন হবে না, তখন শেষ ভিডিও ফ্রেমটি অতিক্রম করার পর ক্লায়েন্ট NOT_VISIBLE অবস্থার জন্য অনুরোধ করবে বলে আশা করা হয়।

যেকোনো সময়ে যেকোনো স্টেটের জন্য অনুরোধ করা যেতে পারে। যদি ডিসপ্লেটি আগে থেকেই দৃশ্যমান থাকে, তবে VISIBLE_ON_NEXT_FRAME এ সেট করা থাকলে তা দৃশ্যমানই থাকবে। অনুরোধ করা স্টেটটি যদি কোনো অচেনা enum ভ্যালু না হয়, তবে এটি সর্বদা OK রিটার্ন করে; অচেনা enum ভ্যালু হলে INVALID_ARG রিটার্ন করা হয়।

getDisplayState() generates (DisplayState state);

ডিসপ্লের অবস্থা গ্রহণ করে। HAL ইমপ্লিমেন্টেশনের উচিত প্রকৃত বর্তমান অবস্থা রিপোর্ট করা, যা সর্বশেষ অনুরোধ করা অবস্থা থেকে ভিন্ন হতে পারে। ডিসপ্লের অবস্থা পরিবর্তনের জন্য দায়ী লজিকটি ডিভাইস লেয়ারের উপরে থাকা উচিত, যার ফলে HAL ইমপ্লিমেন্টেশনের পক্ষে স্বতঃস্ফূর্তভাবে ডিসপ্লের অবস্থা পরিবর্তন করা অনাকাঙ্ক্ষিত।

getTargetBuffer() generates (handle bufferHandle);

ডিসপ্লের সাথে যুক্ত একটি ফ্রেম বাফারের হ্যান্ডেল ফেরত দেয়। এই বাফারটি সফটওয়্যার এবং/অথবা জিএল দ্বারা লক করা এবং এতে লেখা হতে পারে। ডিসপ্লেটি আর দৃশ্যমান না থাকলেও, returnTargetBufferForDisplay() কল করার মাধ্যমে এই বাফারটি অবশ্যই ফেরত দিতে হবে।

যদিও প্রোপ্রাইটারি বাফার ফরম্যাট প্রযুক্তিগতভাবে সম্ভব, সামঞ্জস্যতা পরীক্ষার জন্য বাফারটিকে চারটি সমর্থিত ফরম্যাটের মধ্যে একটিতে থাকতে হবে: NV21 (YCrCb 4:2:0 সেমি-প্ল্যানার), YV12 (YCrCb 4:2:0 প্ল্যানার), YUYV (YCrCb 4:2:2 ইন্টারলিভড), RGBA (৩২ বিট R:G:B:x), BGRA (৩২ বিট B:G:R:x)। নির্বাচিত ফরম্যাটটি অবশ্যই প্ল্যাটফর্মের GLES ইমপ্লিমেন্টেশনে একটি বৈধ GL রেন্ডার টার্গেট হতে হবে।

ত্রুটি ঘটলে, একটি নাল হ্যান্ডেলসহ বাফার ফেরত দেওয়া হয়, কিন্তু এই ধরনের বাফারকে returnTargetBufferForDisplay এ ফেরত পাঠানোর প্রয়োজন নেই।

returnTargetBufferForDisplay(handle bufferHandle) generates (EvsResult result);

ডিসপ্লেকে জানায় যে বাফারটি প্রদর্শনের জন্য প্রস্তুত। শুধুমাত্র getTargetBuffer() কলের মাধ্যমে প্রাপ্ত বাফারগুলোই এই কলের জন্য বৈধ, এবং ক্লায়েন্ট অ্যাপ BufferDesc এর বিষয়বস্তু পরিবর্তন করতে পারবে না। এই কলের পরে, বাফারটি ক্লায়েন্টের ব্যবহারের জন্য আর বৈধ থাকে না। সফল হলে OK রিটার্ন করে, অথবা উপযুক্ত এরর কোড রিটার্ন করে, যার মধ্যে INVALID_ARG বা BUFFER_NOT_AVAILABLE অন্তর্ভুক্ত থাকতে পারে।

struct DisplayDesc {
    string  display_id;
    int32   vendor_flags;  // Opaque value
}

এটি একটি EVS ডিসপ্লের মৌলিক বৈশিষ্ট্য বর্ণনা করে এবং একটি EVS বাস্তবায়নের জন্য এটি আবশ্যক। EVS ডিসপ্লেটির বর্ণনা দেওয়ার জন্য এই কাঠামোটি পূরণ করার দায়িত্ব HAL-এর। এটি একটি ভৌত ​​ডিসপ্লে অথবা একটি ভার্চুয়াল ডিসপ্লে হতে পারে, যা অন্য কোনো প্রেজেন্টেশন ডিভাইসের উপর স্থাপন করা বা মিশ্রিত করা থাকে।

  • display_id . একটি স্ট্রিং যা ডিসপ্লেটিকে অনন্যভাবে শনাক্ত করে। এটি ডিভাইসটির কার্নেল ডিভাইসের নাম, অথবা ডিভাইসটির কোনো নাম, যেমন rearview হতে পারে। এই স্ট্রিংটির মান HAL ইমপ্লিমেন্টেশন দ্বারা নির্বাচিত হয় এবং এর উপরের স্ট্যাক দ্বারা অস্বচ্ছভাবে ব্যবহৃত হয়।
  • vendor_flags . ড্রাইভার থেকে একটি কাস্টম EVS অ্যাপে বিশেষায়িত ক্যামেরা তথ্য অস্বচ্ছভাবে পাঠানোর একটি পদ্ধতি। এই তথ্য ড্রাইভার থেকে EVS অ্যাপে অপরিবর্তিতভাবে পাঠানো হয় এবং অ্যাপটি চাইলে তা উপেক্ষা করতে পারে।
enum DisplayState : uint32 {
    NOT_OPEN,               // Display has not been opened yet
    NOT_VISIBLE,            // Display is inhibited
    VISIBLE_ON_NEXT_FRAME,  // Will become visible with next frame
    VISIBLE,                // Display is currently active
    DEAD,                   // Display is not available. Interface should be closed
}

EVS ডিসপ্লের অবস্থা বর্ণনা করে, যা নিষ্ক্রিয় (ড্রাইভারের কাছে অদৃশ্য) বা সক্রিয় (ড্রাইভারকে ছবি প্রদর্শনকারী) হতে পারে। এর মধ্যে একটি ক্ষণস্থায়ী অবস্থাও অন্তর্ভুক্ত, যেখানে ডিসপ্লেটি তখনও দৃশ্যমান নয়, কিন্তু returnTargetBufferForDisplay() কলের মাধ্যমে পরবর্তী ফ্রেমের ছবি সরবরাহের সাথে সাথে দৃশ্যমান হওয়ার জন্য প্রস্তুত থাকে।

ইভিএস ম্যানেজার

ইভিএস ম্যানেজার বাহ্যিক ক্যামেরার দৃশ্য সংগ্রহ ও উপস্থাপনের জন্য ইভিএস সিস্টেমের পাবলিক ইন্টারফেস প্রদান করে। যেখানে হার্ডওয়্যার ড্রাইভার প্রতিটি রিসোর্সের (ক্যামেরা বা ডিসপ্লে) জন্য কেবল একটি সক্রিয় ইন্টারফেসের অনুমতি দেয়, সেখানে ইভিএস ম্যানেজার ক্যামেরাগুলোতে যৌথ অ্যাক্সেসের সুবিধা প্রদান করে। একটিমাত্র প্রধান ইভিএস অ্যাপ হলো ইভিএস ম্যানেজারের প্রথম ক্লায়েন্ট, এবং এটিই একমাত্র ক্লায়েন্ট যাকে ডিসপ্লে ডেটা লেখার অনুমতি দেওয়া হয় (অতিরিক্ত ক্লায়েন্টদের ক্যামেরার ছবিতে শুধুমাত্র পড়ার (read-only) অ্যাক্সেস দেওয়া যেতে পারে)।

EVS ম্যানেজার অন্তর্নিহিত HAL ড্রাইভারগুলোর মতোই API প্রয়োগ করে এবং একাধিক যুগপৎ ক্লায়েন্টকে সমর্থন করার মাধ্যমে বর্ধিত পরিষেবা প্রদান করে (একাধিক ক্লায়েন্ট EVS ম্যানেজারের মাধ্যমে একটি ক্যামেরা খুলতে এবং ভিডিও স্ট্রিম গ্রহণ করতে পারে)।

ইভিএস ম্যানেজার এবং ইভিএস হার্ডওয়্যার এপিআই ডায়াগ্রাম।
চিত্র ২. ইভিএস ম্যানেজার অন্তর্নিহিত ইভিএস হার্ডওয়্যার এপিআই-কে প্রতিফলিত করে।

EVS হার্ডওয়্যার HAL ইমপ্লিমেন্টেশন বা EVS ম্যানেজার API-এর মাধ্যমে কাজ করার সময় অ্যাপগুলো কোনো পার্থক্য দেখতে পায় না, শুধু এইটুকু ছাড়া যে EVS ম্যানেজার API একই সাথে একাধিক ক্যামেরা স্ট্রিম অ্যাক্সেসের সুযোগ দেয়। EVS ম্যানেজার নিজেই EVS হার্ডওয়্যার HAL লেয়ারের একমাত্র অনুমোদিত ক্লায়েন্ট এবং এটি EVS হার্ডওয়্যার HAL-এর প্রক্সি হিসেবে কাজ করে।

নিম্নলিখিত বিভাগগুলিতে শুধুমাত্র সেই কলগুলির বর্ণনা দেওয়া হয়েছে যেগুলির EVS ম্যানেজার বাস্তবায়নে একটি ভিন্ন (বর্ধিত) আচরণ রয়েছে; বাকি কলগুলি EVS HAL বর্ণনার অনুরূপ।

IEvsEnumerator

openCamera(string camera_id) generates (IEvsCamera camera);

অনন্য camera_id স্ট্রিং দ্বারা চিহ্নিত একটি নির্দিষ্ট ক্যামেরার সাথে ইন্টারঅ্যাক্ট করার জন্য ব্যবহৃত একটি ইন্টারফেস অবজেক্ট সংগ্রহ করে। ব্যর্থ হলে NULL রিটার্ন করে। EVS ম্যানেজার লেয়ারে, যতক্ষণ পর্যন্ত পর্যাপ্ত সিস্টেম রিসোর্স উপলব্ধ থাকে, ততক্ষণ অন্য কোনো প্রসেস দ্বারা ইতিমধ্যে খোলা একটি ক্যামেরা পুনরায় খোলা যেতে পারে, যা একাধিক কনজিউমার অ্যাপে ভিডিও স্ট্রিম টিয়িং (teeing) করার সুযোগ দেয়। EVS ম্যানেজার লেয়ারের camera_id স্ট্রিংগুলো EVS হার্ডওয়্যার লেয়ারে রিপোর্ট করা স্ট্রিংগুলোর মতোই।

আইইভিএসক্যামেরা

EVS ম্যানেজার দ্বারা প্রদত্ত IEvsCamera ইমপ্লিমেন্টেশনটি অভ্যন্তরীণভাবে ভার্চুয়ালাইজড, ফলে একটি ক্লায়েন্ট কর্তৃক ক্যামেরার উপর পরিচালিত অপারেশনগুলো অন্য ক্লায়েন্টদের প্রভাবিত করে না এবং তারা তাদের নিজ নিজ ক্যামেরায় স্বাধীন অ্যাক্সেস বজায় রাখে।

startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);

ভিডিও স্ট্রিম চালু করে। ক্লায়েন্টরা একই অন্তর্নিহিত ক্যামেরায় স্বাধীনভাবে ভিডিও স্ট্রিম চালু এবং বন্ধ করতে পারে। প্রথম ক্লায়েন্ট চালু হলে অন্তর্নিহিত ক্যামেরাটিও চালু হয়।

doneWithFrame(uint32 frameId, handle bufferHandle) generates (EvsResult result);

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

stopVideoStream();

একটি ভিডিও স্ট্রিম বন্ধ করে। প্রতিটি ক্লায়েন্ট অন্য ক্লায়েন্টদের প্রভাবিত না করেই যেকোনো সময় তার ভিডিও স্ট্রিম বন্ধ করতে পারে। হার্ডওয়্যার স্তরে থাকা অন্তর্নিহিত ক্যামেরা স্ট্রিমটি তখন বন্ধ হয়ে যায়, যখন কোনো নির্দিষ্ট ক্যামেরার সর্বশেষ ক্লায়েন্ট তার স্ট্রিমটি বন্ধ করে।

setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);

এটি একটি ড্রাইভার-নির্দিষ্ট মান পাঠায়, যা সম্ভাব্যভাবে একটি ক্লায়েন্টকে অন্য ক্লায়েন্টকে প্রভাবিত করতে সক্ষম করে। যেহেতু EVS ম্যানেজার ভেন্ডর-সংজ্ঞায়িত কন্ট্রোল ওয়ার্ডগুলোর তাৎপর্য বুঝতে পারে না, তাই সেগুলোকে ভার্চুয়ালাইজ করা হয় না এবং এর যেকোনো পার্শ্বপ্রতিক্রিয়া একটি নির্দিষ্ট ক্যামেরার সমস্ত ক্লায়েন্টের উপর প্রযোজ্য হয়। উদাহরণস্বরূপ, যদি কোনো ভেন্ডর ফ্রেম রেট পরিবর্তন করার জন্য এই কলটি ব্যবহার করে, তবে প্রভাবিত হার্ডওয়্যার লেয়ার ক্যামেরার সমস্ত ক্লায়েন্ট নতুন রেটে ফ্রেম পাবে।

আইইভিএসডিসপ্লে

এমনকি EVS ম্যানেজার স্তরেও ডিসপ্লেটির কেবল একজন মালিকই অনুমোদিত। ম্যানেজার কোনো অতিরিক্ত কার্যকারিতা যোগ করে না এবং কেবল IEvsDisplay ইন্টারফেসটিকে সরাসরি অন্তর্নিহিত HAL ইমপ্লিমেন্টেশনে পাঠিয়ে দেয়।

ইভিএস অ্যাপ

অ্যান্ড্রয়েডে একটি EVS অ্যাপের নেটিভ C++ রেফারেন্স ইমপ্লিমেন্টেশন রয়েছে, যা EVS ম্যানেজার এবং ভেহিকেল HAL-এর সাথে যোগাযোগ করে গাড়ির পেছনের ক্যামেরার প্রাথমিক ফাংশনগুলো প্রদান করে। আশা করা যায়, সিস্টেম বুট হওয়ার একেবারে শুরুর দিকেই অ্যাপটি চালু হবে এবং উপলব্ধ ক্যামেরা ও গাড়ির অবস্থার (গিয়ার এবং টার্ন সিগন্যালের অবস্থা) ওপর নির্ভর করে উপযুক্ত ভিডিও দেখানো হবে। OEM-রা তাদের নিজস্ব যানবাহন-নির্দিষ্ট লজিক এবং উপস্থাপনা দিয়ে EVS অ্যাপটি পরিবর্তন বা প্রতিস্থাপন করতে পারে।

চিত্র ৩. EVS অ্যাপের নমুনা লজিক, ক্যামেরার তালিকা সংগ্রহ।


চিত্র ৪. EVS অ্যাপের নমুনা লজিক, ফ্রেম গ্রহণ কলব্যাক।

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

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

EVS ডিসপ্লে HAL-এ EGL/সারফেসফ্লিঙ্গার ব্যবহার করুন

এই অংশে ব্যাখ্যা করা হয়েছে কিভাবে অ্যান্ড্রয়েড ১০-এ EGL ব্যবহার করে একটি EVS ডিসপ্লে HAL ইমপ্লিমেন্টেশন রেন্ডার করা যায়।

একটি EVS HAL রেফারেন্স ইমপ্লিমেন্টেশন স্ক্রিনে ক্যামেরা প্রিভিউ রেন্ডার করার জন্য EGL ব্যবহার করে এবং টার্গেট EGL রেন্ডার সারফেস তৈরি করতে libgui ব্যবহার করে। Android 8 (এবং এর পরবর্তী সংস্করণ)-এ, libgui VNDK-প্রাইভেট হিসেবে শ্রেণীবদ্ধ করা হয়েছে, যা VNDK লাইব্রেরির জন্য উপলব্ধ এমন একদল লাইব্রেরিকে বোঝায় যা ভেন্ডর প্রসেস ব্যবহার করতে পারে না। যেহেতু HAL ইমপ্লিমেন্টেশনগুলোকে অবশ্যই ভেন্ডর পার্টিশনে থাকতে হয়, তাই ভেন্ডরদের HAL ইমপ্লিমেন্টেশনে সারফেস ব্যবহার করা থেকে বিরত রাখা হয়।

ভেন্ডর প্রসেসের জন্য লিবগুই তৈরি করা হচ্ছে

EVS ডিসপ্লে HAL ইমপ্লিমেন্টেশনে EGL/SurfaceFlinger ব্যবহার করার জন্য libgui এর ব্যবহারই একমাত্র উপায়। libgui ইমপ্লিমেন্ট করার সবচেয়ে সহজ উপায় হলো বিল্ড স্ক্রিপ্টে একটি অতিরিক্ত বিল্ড টার্গেট ব্যবহার করে সরাসরি frameworks/native/libs/gui-এর মাধ্যমে। এই টার্গেটটি libgui টার্গেটের মতোই, শুধু দুটি ফিল্ড অতিরিক্তভাবে যুক্ত থাকে:

  • name
  • vendor_available
cc_library_shared {
    name: "libgui_vendor",
    vendor_available: true,
    vndk: {
        enabled: false,
    },
    double_loadable: true,

defaults: ["libgui_bufferqueue-defaults"],
srcs: [ // bufferhub is not used when building libgui for vendors target: { vendor: { cflags: [ "-DNO_BUFFERHUB", "-DNO_INPUT", ],

দ্রষ্টব্য: ভেন্ডর টার্গেটগুলো NO_INPUT ম্যাক্রো দিয়ে তৈরি করা হয়, যা পার্সেল ডেটা থেকে একটি ৩২-বিটের ওয়ার্ড সরিয়ে দেয়। যেহেতু SurfaceFlinger এই অপসারিত ফিল্ডটি প্রত্যাশা করে, তাই SurfaceFlinger পার্সেলটি পার্স করতে ব্যর্থ হয়। এটি একটি fcntl ব্যর্থতা হিসাবে পরিলক্ষিত হয়:

W Parcel  : Attempt to read object from Parcel 0x78d9cffad8 at offset 428 that is not in the object list
E Parcel  : fcntl(F_DUPFD_CLOEXEC) failed in Parcel::read, i is 0, fds[i] is 0, fd_count is 20, error: Unknown error 2147483647
W Parcel  : Attempt to read object from Parcel 0x78d9cffad8 at offset 544 that is not in the object list

এই অবস্থার সমাধান করতে:

diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 6066421fa..25cf5f0ce 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -54,6 +54,9 @@ status_t layer_state_t::write(Parcel& output) const
    output.writeFloat(color.b);
#ifndef NO_INPUT
    inputInfo.write(output);
+#else
+    // Write a dummy 32-bit word.
+    output.writeInt32(0);
#endif
    output.write(transparentRegion);
    output.writeUint32(transform);

নমুনা বিল্ড নির্দেশাবলী নিচে দেওয়া হলো। আপনি $(ANDROID_PRODUCT_OUT)/system/lib64/libgui_vendor.so ফাইলটি পাবেন বলে আশা করা হচ্ছে।

$ cd <your_android_source_tree_top>
$ . ./build/envsetup.
$ lunch <product_name>-<build_variant>
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=10
TARGET_PRODUCT=<product_name>
TARGET_BUILD_VARIANT=<build_variant>
TARGET_BUILD_TYPE=release
TARGET_ARCH=arm64
TARGET_ARCH_VARIANT=armv8-a
TARGET_CPU_VARIANT=generic
TARGET_2ND_ARCH=arm
TARGET_2ND_ARCH_VARIANT=armv7-a-neon
TARGET_2ND_CPU_VARIANT=cortex-a9
HOST_ARCH=x86_64
HOST_2ND_ARCH=x86
HOST_OS=linux
HOST_OS_EXTRA=<host_linux_version>
HOST_CROSS_OS=windows
HOST_CROSS_ARCH=x86
HOST_CROSS_2ND_ARCH=x86_64
HOST_BUILD_TYPE=release
BUILD_ID=QT
OUT_DIR=out
============================================

$ m -j libgui_vendor … $ find $ANDROID_PRODUCT_OUT/system -name "libgui_vendor*" .../out/target/product/hawk/system/lib64/libgui_vendor.so .../out/target/product/hawk/system/lib/libgui_vendor.so

EVS HAL বাস্তবায়নে বাইন্ডার ব্যবহার করুন

অ্যান্ড্রয়েড ৮ (এবং এর পরবর্তী সংস্করণ)-এ, /dev/binder ডিভাইস নোডটি শুধুমাত্র ফ্রেমওয়ার্ক প্রসেসগুলোর জন্য সংরক্ষিত হয়ে যায় এবং ফলস্বরূপ, ভেন্ডর প্রসেসগুলোর জন্য এটি অ্যাক্সেসযোগ্য থাকে না। এর পরিবর্তে, ভেন্ডর প্রসেসগুলোর /dev/hwbinder ব্যবহার করা উচিত এবং যেকোনো AIDL ইন্টারফেসকে HIDL-এ রূপান্তর করতে হবে। যারা ভেন্ডর প্রসেসগুলোর মধ্যে AIDL ইন্টারফেস ব্যবহার চালিয়ে যেতে চান, তারা বাইন্ডার ডোমেইন, /dev/vndbinder ব্যবহার করুন।

আইপিসি ডোমেইন বর্ণনা
/dev/binder AIDL ইন্টারফেস ব্যবহার করে ফ্রেমওয়ার্ক/অ্যাপ প্রসেসগুলির মধ্যে IPC
/dev/hwbinder HIDL ইন্টারফেস ব্যবহার করে ফ্রেমওয়ার্ক/ভেন্ডর প্রসেসগুলোর মধ্যে IPC
HIDL ইন্টারফেস সহ ভেন্ডর প্রসেসগুলির মধ্যে IPC
/dev/vndbinder AIDL ইন্টারফেস ব্যবহার করে ভেন্ডর/ভেন্ডর প্রসেসগুলির মধ্যে IPC

যদিও সারফেসফ্লিঙ্গার AIDL ইন্টারফেস সংজ্ঞায়িত করে, ভেন্ডর প্রসেসগুলো ফ্রেমওয়ার্ক প্রসেসের সাথে যোগাযোগের জন্য শুধুমাত্র HIDL ইন্টারফেস ব্যবহার করতে পারে। বিদ্যমান AIDL ইন্টারফেসগুলোকে HIDL-এ রূপান্তর করতে যথেষ্ট পরিমাণ কাজ করতে হয়। সৌভাগ্যবশত, অ্যান্ড্রয়েড libbinder এর জন্য বাইন্ডার ড্রাইভার নির্বাচন করার একটি পদ্ধতি প্রদান করে, যার সাথে ইউজারস্পেস লাইব্রেরি প্রসেসগুলো লিঙ্ক করা থাকে।

diff --git a/evs/sampleDriver/service.cpp b/evs/sampleDriver/service.cpp
index d8fb3166..5fd02935 100644
--- a/evs/sampleDriver/service.cpp
+++ b/evs/sampleDriver/service.cpp
@@ -21,6 +21,7 @@
#include <utils/Errors.h>
#include <utils/StrongPointer.h>
#include <utils/Log.h>
+#include <binder/ProcessState.h>

#include "ServiceNames.h"
#include "EvsEnumerator.h"
@@ -43,6 +44,9 @@ using namespace android;
int main() {
    ALOGI("EVS Hardware Enumerator service is starting");


+    // Use /dev/binder for SurfaceFlinger
+    ProcessState::initWithDriver("/dev/binder");
+


    // Start a thread to listen to video device addition events.
    std::atomic<bool> running { true };
    std::thread ueventHandler(EvsEnumerator::EvsUeventThread, std::ref(running));

দ্রষ্টব্য: ভেন্ডর প্রসেসগুলোকে Process বা IPCThreadState কল করার আগে , অথবা যেকোনো বাইন্ডার কল করার আগে এটি কল করতে হবে।

SELinux নীতিগুলি

যদি ডিভাইস ইমপ্লিমেন্টেশনটি ফুল ট্রেবল হয়, তাহলে SELinux ভেন্ডর প্রসেসগুলোকে /dev/binder ব্যবহার করতে বাধা দেয়। উদাহরণস্বরূপ, একটি EVS HAL স্যাম্পল ইমপ্লিমেন্টেশনকে hal_evs_driver ডোমেইনে অ্যাসাইন করা হয় এবং এর জন্য binder_device ডোমেইনে r/w পারমিশন প্রয়োজন হয়।

W ProcessState: Opening '/dev/binder' failed: Permission denied
F ProcessState: Binder driver could not be opened. Terminating.
F libc    : Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 9145 (android.hardwar), pid 9145 (android.hardwar)
W android.hardwar: type=1400 audit(0.0:974): avc: denied { read write } for name="binder" dev="tmpfs" ino=2208 scontext=u:r:hal_evs_driver:s0 tcontext=u:object_r:binder_device:s0 tclass=chr_file permissive=0

তবে, এই অনুমতিগুলো যোগ করার ফলে বিল্ড ব্যর্থ হয়, কারণ এটি একটি ফুল-ট্রেবল ডিভাইসের জন্য system/sepolicy/domain.te তে সংজ্ঞায়িত নিম্নলিখিত neverallow নিয়মগুলো লঙ্ঘন করে।

libsepol.report_failure: neverallow on line 631 of system/sepolicy/public/domain.te (or line 12436 of policy.conf) violated by allow hal_evs_driver binder_device:chr_file { read write };
libsepol.check_assertions: 1 neverallow failures occurred
full_treble_only(`
neverallow {
    domain
    -coredomain
    -appdomain
    -binder_in_vendor_violators
} binder_device:chr_file rw_file_perms;
')

binder_in_vendor_violators হলো একটি অ্যাট্রিবিউট যা বাগ শনাক্ত করতে এবং উন্নয়নে দিকনির্দেশনা দিতে ব্যবহৃত হয়। এটি উপরে বর্ণিত অ্যান্ড্রয়েড ১০ ভায়োলেশনটি সমাধান করতেও ব্যবহার করা যেতে পারে।

diff --git a/evs/sepolicy/evs_driver.te b/evs/sepolicy/evs_driver.te
index f1f31e9fc..6ee67d88e 100644
--- a/evs/sepolicy/evs_driver.te
+++ b/evs/sepolicy/evs_driver.te
@@ -3,6 +3,9 @@ type hal_evs_driver, domain, coredomain;
hal_server_domain(hal_evs_driver, hal_evs)
hal_client_domain(hal_evs_driver, hal_evs)

+# Allow to use /dev/binder
+typeattribute hal_evs_driver binder_in_vendor_violators;
+
# allow init to launch processes in this context
type hal_evs_driver_exec, exec_type, file_type, system_file_type;
init_daemon_domain(hal_evs_driver)

ভেন্ডর প্রক্রিয়া হিসেবে EVS HAL রেফারেন্স বাস্তবায়ন তৈরি করুন

রেফারেন্স হিসেবে, আপনি packages/services/Car/evs/Android.mk এ নিম্নলিখিত পরিবর্তনগুলি প্রয়োগ করতে পারেন। নিশ্চিত হয়ে নেবেন যে বর্ণিত সমস্ত পরিবর্তন আপনার ইমপ্লিমেন্টেশনে কাজ করছে।

diff --git a/evs/sampleDriver/Android.mk b/evs/sampleDriver/Android.mk
index 734feea7d..0d257214d 100644
--- a/evs/sampleDriver/Android.mk
+++ b/evs/sampleDriver/Android.mk
@@ -16,7 +16,7 @@ LOCAL_SRC_FILES := \
LOCAL_SHARED_LIBRARIES := \
    android.hardware.automotive.evs@1.0 \
    libui \
-    libgui \
+    libgui_vendor \
    libEGL \
    libGLESv2 \
    libbase \
@@ -33,6 +33,7 @@ LOCAL_SHARED_LIBRARIES := \
LOCAL_INIT_RC := android.hardware.automotive.evs@1.0-sample.rc

LOCAL_MODULE := android.hardware.automotive.evs@1.0-sample
+LOCAL_PROPRIETARY_MODULE := true

LOCAL_MODULE_TAGS := optional
LOCAL_STRIP_MODULE := keep_symbols
@@ -40,6 +41,7 @@ LOCAL_STRIP_MODULE := keep_symbols
LOCAL_CFLAGS += -DLOG_TAG=\"EvsSampleDriver\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+LOCAL_CFLAGS += -Iframeworks/native/include

#NOTE:  It can be helpful, while debugging, to disable optimizations
#LOCAL_CFLAGS += -O0 -g
diff --git a/evs/sampleDriver/service.cpp b/evs/sampleDriver/service.cpp
index d8fb31669..5fd029358 100644
--- a/evs/sampleDriver/service.cpp
+++ b/evs/sampleDriver/service.cpp
@@ -21,6 +21,7 @@
#include <utils/Errors.h>
#include <utils/StrongPointer.h>
#include <utils/Log.h>
+#include <binder/ProcessState.h>

#include "ServiceNames.h"
#include "EvsEnumerator.h"
@@ -43,6 +44,9 @@ using namespace android;
int main() {
    ALOGI("EVS Hardware Enumerator service is starting");
+    // Use /dev/binder for SurfaceFlinger
+    ProcessState::initWithDriver("/dev/binder");
+
     // Start a thread to listen video device addition events.
    std::atomic<bool> running { true };
    std::thread ueventHandler(EvsEnumerator::EvsUeventThread, std::ref(running));
diff --git a/evs/sepolicy/evs_driver.te b/evs/sepolicy/evs_driver.te
index f1f31e9fc..632fc7337 100644
--- a/evs/sepolicy/evs_driver.te
+++ b/evs/sepolicy/evs_driver.te
@@ -3,6 +3,9 @@ type hal_evs_driver, domain, coredomain;
hal_server_domain(hal_evs_driver, hal_evs)
hal_client_domain(hal_evs_driver, hal_evs)

+# allow to use /dev/binder
+typeattribute hal_evs_driver binder_in_vendor_violators;
+
# allow init to launch processes in this context
type hal_evs_driver_exec, exec_type, file_type, system_file_type;
init_daemon_domain(hal_evs_driver)
@@ -22,3 +25,7 @@ allow hal_evs_driver ion_device:chr_file r_file_perms;

# Allow the driver to access kobject uevents
allow hal_evs_driver self:netlink_kobject_uevent_socket create_socket_perms_no_ioctl;
+
+# Allow the driver to use the binder device
+allow hal_evs_driver binder_device:chr_file rw_file_perms;