ক্যামেরা ক্যাপচার সেশন ও অনুরোধ

মনে রাখবেন: এই পৃষ্ঠায় Camera2 প্যাকেজের কথা বলা হয়েছে। আপনার অ্যাপে Camera2 থেকে নির্দিষ্ট, লো-লেভেল ফিচারের প্রয়োজন না হলে, আমরা CameraX ব্যবহার করার সাজেশন দিই। CameraX ও Camera2, দু'টিই Android 5.0 (API লেভেল ২১) ও এর পরের যেকোনও ভার্সনে কাজ করে।

একটি Android-পরিচালিত ডিভাইসে একাধিক ক্যামেরা থাকতে পারে। প্রতিটি ক্যামেরা হল একটি CameraDevice, এবং একটি CameraDevice একই সাথে একাধিক স্ট্রিম আউটপুট করতে পারে।

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

ছবি ১. বিল্ডিং আ ইউনিভার্সাল ক্যামেরা অ্যাপ থেকে পাওয়া ছবি (Google I/O ‘১৮)

সমান্তরাল প্রসেসিং থেকে বোঝা যায় যে CPU, GPU বা অন্যান্য প্রসেসর থেকে উপলভ্য প্রসেসিং পাওয়ারের উপর নির্ভর করে পারফর্ম্যান্সের সীমা থাকতে পারে। কোনও পাইপলাইন ইনকামিং ফ্রেমের সাথে তাল মিলিয়ে চলতে না পারলে, সেটি ফ্রেম ড্রপ করা শুরু করে।

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

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

তবে, স্ট্রিম ব্যবহারিক প্রয়োগ, ক্যাপচার সেশন স্ট্রিম করার জন্য CameraDevice ব্যবহার করার আগের পদ্ধতিকে উন্নত ও প্রসারিত করে, যা আপনাকে নিজের নির্দিষ্ট ব্যবহারিক প্রয়োগের জন্য ক্যামেরা স্ট্রিম অপ্টিমাইজ করতে দেয়। যেমন, ভিডিও কল অপ্টিমাইজ করার সময় এটি ব্যাটারির আয়ু উন্নত করতে পারে।

CameraCaptureSession-এ CameraDevice-এর সাথে যুক্ত থাকা সব সম্ভাব্য পাইপলাইন সম্পর্কে বর্ণনা করা থাকে। সেশন তৈরি হয়ে গেলে, আপনি পাইপলাইন যোগ করতে বা সরিয়ে দিতে পারবেন না। CameraCaptureSession CaptureRequest-এর একটি সারি বজায় রাখে, যা অ্যাক্টিভ কনফিগারেশন হয়ে যায়।

CaptureRequest কোয়েরিতে একটি কনফিগারেশন যোগ করে এবং CameraDevice থেকে ফ্রেম পাওয়ার জন্য একটি, একাধিক বা উপলভ্য সব পাইপলাইন বেছে নেয়। আপনি একটি ক্যাপচার সেশনের সময়সীমার মধ্যে একাধিক ক্যাপচার অনুরোধ পাঠাতে পারবেন। প্রতিটি অনুরোধ অ্যাক্টিভ কনফিগারেশন এবং আউটপুট পাইপলাইনের সেট পরিবর্তন করতে পারে যা র ইমেজ পায়।

আরও ভালো পারফর্ম্যান্সের জন্য স্ট্রিম ব্যবহারিক প্রয়োগ ব্যবহার করা

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

এর ফলে ক্যামেরা ডিভাইস, প্রতিটি স্ট্রিমের জন্য ব্যবহারকারীর পরিস্থিতি অনুযায়ী ক্যামেরা হার্ডওয়্যার ও সফ্টওয়্যার পাইপলাইন অপ্টিমাইজ করতে পারে। স্ট্রিম ব্যবহারের কেস সম্পর্কে আরও তথ্যের জন্য, setStreamUseCase দেখুন।

স্ট্রিম ব্যবহারের ধরন আপনাকে নির্দিষ্ট ক্যামেরা স্ট্রিম কীভাবে আরও বিস্তারিতভাবে ব্যবহার করা হয় তা নির্দিষ্ট করতে দেয়, এর পাশাপাশি CameraDevice.createCaptureRequest()-এ টেমপ্লেট সেট করা যায়। এর ফলে ক্যামেরা হার্ডওয়্যার, নির্দিষ্ট ব্যবহারের ক্ষেত্রে উপযুক্ত কোয়ালিটি বা লেটেন্সি ট্রেডঅফের উপর ভিত্তি করে টিউনিং, সেন্সর মোড বা ক্যামেরা সেন্সর সেটিংসের মতো প্যারামিটার অপ্টিমাইজ করতে পারে।

স্ট্রিম ব্যবহারের উদাহরণগুলির মধ্যে এগুলি অন্তর্ভুক্ত:

  • DEFAULT: আগে থেকে থাকা সব অ্যাপ্লিকেশনের আচরণ কভার করে। এটি কোনও স্ট্রিম ব্যবহারিক ক্ষেত্র সেট না করার সমতুল্য।

  • PREVIEW: Viewfinder বা ইন-অ্যাপ ইমেজ বিশ্লেষণের জন্য সাজেস্ট করা হয়।

  • STILL_CAPTURE: হাই-কোয়ালিটি হাই-রেজোলিউশন ক্যাপচারের জন্য অপ্টিমাইজ করা হয়েছে এবং প্রিভিউয়ের মতো ফ্রেম রেট বজায় রাখার কথা নয়।

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

  • VIDEO_CALL: দীর্ঘক্ষণ ধরে ক্যামেরা ব্যবহারের ক্ষেত্রে সাজেস্ট করা হয়, যেখানে ব্যাটারি দ্রুত শেষ হয়ে যাওয়া একটি সমস্যা।

  • PREVIEW_VIDEO_STILL: সোশ্যাল মিডিয়া অ্যাপ বা সিঙ্গেল স্ট্রিম ব্যবহারের ক্ষেত্রে সাজেস্ট করা হয় । এটি একটি বহুমুখী স্ট্রিম।

  • VENDOR_START: OEM-এর সংজ্ঞায়িত ব্যবহারিক ক্ষেত্রের জন্য ব্যবহার করা হয়।

CameraCaptureSession তৈরি করা

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

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

Kotlin

// Retrieve the target surfaces, which might be coming from a number of places:
// 1. SurfaceView, if you want to display the image directly to the user
// 2. ImageReader, if you want to read each frame or perform frame-by-frame
// analysis
// 3. OpenGL Texture or TextureView, although discouraged for maintainability
      reasons
// 4. RenderScript.Allocation, if you want to do parallel processing
val surfaceView = findViewById<SurfaceView>(...)
val imageReader = ImageReader.newInstance(...)

// Remember to call this only *after* SurfaceHolder.Callback.surfaceCreated()
val previewSurface = surfaceView.holder.surface
val imReaderSurface = imageReader.surface
val targets = listOf(previewSurface, imReaderSurface)

// Create a capture session using the predefined targets; this also involves
// defining the session state callback to be notified of when the session is
// ready
// Setup Stream Use Case while setting up your Output Configuration.
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
fun configureSession(device: CameraDevice, targets: List<Surface>){
    val configs = mutableListOf<OutputConfiguration>()
    val streamUseCase = CameraMetadata
        .SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL

    targets.forEach {
        val config = OutputConfiguration(it)
        config.streamUseCase = streamUseCase.toLong()
        configs.add(config)
    }
    ...
    device.createCaptureSession(session)
}

জাভা

// Retrieve the target surfaces, which might be coming from a number of places:
// 1. SurfaceView, if you want to display the image directly to the user
// 2. ImageReader, if you want to read each frame or perform frame-by-frame
      analysis
// 3. RenderScript.Allocation, if you want to do parallel processing
// 4. OpenGL Texture or TextureView, although discouraged for maintainability
      reasons
Surface surfaceView = findViewById<SurfaceView>(...);
ImageReader imageReader = ImageReader.newInstance(...);

// Remember to call this only *after* SurfaceHolder.Callback.surfaceCreated()
Surface previewSurface = surfaceView.getHolder().getSurface();
Surface imageSurface = imageReader.getSurface();
List<Surface> targets = Arrays.asList(previewSurface, imageSurface);

// Create a capture session using the predefined targets; this also involves defining the
// session state callback to be notified of when the session is ready
private void configureSession(CameraDevice device, List<Surface> targets){
    ArrayList<OutputConfiguration> configs= new ArrayList()
    String streamUseCase=  CameraMetadata
        .SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL

    for(Surface s : targets){
        OutputConfiguration config = new OutputConfiguration(s)
        config.setStreamUseCase(String.toLong(streamUseCase))
        configs.add(config)
}

device.createCaptureSession(session)
}

এই পর্যায়ে, আপনি ক্যামেরার অ্যাক্টিভ কনফিগারেশন নির্ধারণ করেননি। সেশন কনফিগার করা হয়ে গেলে, এটি করার জন্য আপনি ক্যাপচার অনুরোধ তৈরি ও ডিসপ্যাচ করতে পারবেন।

ইনপুটকে সেটির বাফারে লেখার সময় যে ট্রান্সফর্মেশন প্রয়োগ করা হয় তা প্রতিটি টার্গেটের ধরন দ্বারা নির্ধারিত হয়, যা অবশ্যই একটি Surface হতে হবে। অ্যাক্টিভ কনফিগারেশনে থাকা কোনও র ইমেজকে প্রতিটি টার্গেটের জন্য উপযুক্ত ফর্ম্যাটে কীভাবে কনভার্ট করতে হয় তা Android ফ্রেমওয়ার্ক জানে। কনভার্সনটি নির্দিষ্ট Surface-এর পিক্সেল ফর্ম্যাট ও সাইজ দ্বারা নিয়ন্ত্রিত হয়।

ফ্রেমওয়ার্ক তার সেরাটা দেওয়ার চেষ্টা করে, কিন্তু কিছু Surface কনফিগারেশন কম্বিনেশন কাজ নাও করতে পারে, এর ফলে সেশন তৈরি না হওয়া, কোনও অনুরোধ ডিসপ্যাচ করার সময় রানটাইম এরর দেখানো অথবা পারফর্ম্যান্স খারাপ হওয়ার মতো সমস্যা হতে পারে। ফ্রেমওয়ার্ক ডিভাইস, সারফেস ও অনুরোধ প্যারামিটারের নির্দিষ্ট কম্বিনেশনের জন্য গ্যারান্টি প্রদান করে। createCaptureSession() এর ডকুমেন্টেশনে আরও তথ্য দেওয়া আছে।

Single CaptureRequests

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

ক্যাপচার রিকোয়েস্ট বিল্ডার প্যাটার্ন ব্যবহার করে এবং এর মাধ্যমে ডেভেলপাররা অটো-এক্সপোজার, অটো-ফোকাস, এবং লেন্স অ্যাপারচার সহ অনেক আলাদা বিকল্প সেট করতে পারেন। কোনও ফিল্ড সেট করার আগে, নিশ্চিত করুন যে নির্দিষ্ট বিকল্পটি CameraCharacteristics.getAvailableCaptureRequestKeys() কল করে ডিভাইসের জন্য উপলভ্য আছে এবং উপলভ্য অটো-এক্সপোজার মোড-এর মতো উপযুক্ত ক্যামেরা বৈশিষ্ট্য চেক করে দেখে নিন যে কাঙ্ক্ষিত মানটি কাজ করে কিনা।

কোনও পরিবর্তন না করেই প্রিভিউ করার জন্য ডিজাইন করা টেমপ্লেট ব্যবহার করে SurfaceView-এর জন্য ক্যাপচার অনুরোধ তৈরি করতে, CameraDevice.TEMPLATE_PREVIEW ব্যবহার করুন:

Kotlin

val session: CameraCaptureSession = ...  // from CameraCaptureSession.StateCallback
val captureRequest = session.device.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
captureRequest.addTarget(previewSurface)

জাভা

CameraCaptureSession session = ...;  // from CameraCaptureSession.StateCallback
CaptureRequest.Builder captureRequest =
    session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequest.addTarget(previewSurface);

ক্যাপচার অনুরোধ নির্দিষ্ট করা হয়ে গেলে, আপনি এখন ক্যামেরা সেশনে এটি ডিসপ্যাচ করতে পারবেন:

Kotlin

val session: CameraCaptureSession = ...  // from CameraCaptureSession.StateCallback
val captureRequest: CaptureRequest = ...  // from CameraDevice.createCaptureRequest()

// The first null argument corresponds to the capture callback, which you
// provide if you want to retrieve frame metadata or keep track of failed capture
// requests that can indicate dropped frames; the second null argument
// corresponds to the Handler used by the asynchronous callback, which falls
// back to the current thread's looper if null
session.capture(captureRequest.build(), null, null)

জাভা

CameraCaptureSession session = ...;  // from CameraCaptureSession.StateCallback
CaptureRequest captureRequest = ...;  // from CameraDevice.createCaptureRequest()

// The first null argument corresponds to the capture callback, which you
// provide if you want to retrieve frame metadata or keep track of failed
// capture
// requests that can indicate dropped frames; the second null argument
// corresponds to the Handler used by the asynchronous callback, which falls
// back to the current thread's looper if null
session.capture(captureRequest.build(), null, null);

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

CaptureRequest রিপিট করা

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

Kotlin

val session: CameraCaptureSession = ...  // from CameraCaptureSession.StateCallback
val captureRequest: CaptureRequest = ...  // from CameraDevice.createCaptureRequest()

// This keeps sending the capture request as frequently as possible until
// the
// session is torn down or session.stopRepeating() is called
// session.setRepeatingRequest(captureRequest.build(), null, null)

জাভা

CameraCaptureSession session = ...;  // from CameraCaptureSession.StateCallback
CaptureRequest captureRequest = ...;  // from CameraDevice.createCaptureRequest()

// This keeps sending the capture request as frequently as possible until the
// session is torn down or session.stopRepeating() is called
// session.setRepeatingRequest(captureRequest.build(), null, null);

বারবার ক্যাপচার করার অনুরোধ করলে, ক্যামেরা ডিভাইস প্রদান করা CaptureRequest-এ দেওয়া সেটিংস ব্যবহার করে ক্রমাগত ছবি ক্যাপচার করে। এছাড়াও, Camera2 API ব্যবহারকারীদের ক্যামেরা থেকে ভিডিও ক্যাপচার করতে দেয়। এর জন্য GitHub-এ থাকা এই Camera2 স্যাম্পেল রেপোজিটরিতে দেখানো হয়েছে সেইভাবে বারবার CaptureRequests পাঠাতে হয়। এছাড়াও, এটি রিপিটিং বার্স্ট CaptureRequests ব্যবহার করে হাই-স্পিড (স্লো মোশন) ভিডিও ক্যাপচার করার মাধ্যমে স্লো মোশন ভিডিও রেন্ডার করতে পারে, যা GitHub-এ Camera2 স্লো মোশন ভিডিও স্যাম্পেল অ্যাপে দেখানো হয়েছে।

CaptureRequest ইন্টারলিভ করা

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

সেশন প্রথম তৈরি করার সময়, ব্যবহৃত যেকোনও আউটপুট বাফারকে ক্যামেরা সেশনের অংশ হিসেবে কনফিগার করতে হবে । একক ফ্রেম বা বার্স্ট অনুরোধের তুলনায় পুনরাবৃত্ত অনুরোধের অগ্রাধিকার কম থাকে, যা নিম্নলিখিত নমুনাকে কাজ করতে দেয়:

Kotlin

val session: CameraCaptureSession = ...  // from CameraCaptureSession.StateCallback

// Create the repeating request and dispatch it
val repeatingRequest = session.device.createCaptureRequest(
CameraDevice.TEMPLATE_PREVIEW)
repeatingRequest.addTarget(previewSurface)
session.setRepeatingRequest(repeatingRequest.build(), null, null)

// Some time later...

// Create the single request and dispatch it
// NOTE: This can disrupt the ongoing repeating request momentarily
val singleRequest = session.device.createCaptureRequest(
CameraDevice.TEMPLATE_STILL_CAPTURE)
singleRequest.addTarget(imReaderSurface)
session.capture(singleRequest.build(), null, null)

জাভা

CameraCaptureSession session = ...;  // from CameraCaptureSession.StateCallback

// Create the repeating request and dispatch it
CaptureRequest.Builder repeatingRequest =
session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
repeatingRequest.addTarget(previewSurface);
session.setRepeatingRequest(repeatingRequest.build(), null, null);

// Some time later...

// Create the single request and dispatch it
// NOTE: This can disrupt the ongoing repeating request momentarily
CaptureRequest.Builder singleRequest =
session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
singleRequest.addTarget(imReaderSurface);
session.capture(singleRequest.build(), null, null);

তবে এই পদ্ধতিতে একটি অসুবিধা আছে: একটি অনুরোধ ঠিক কখন করা হয় তা আপনি জানতে পারেন না। নিচের ছবিতে, A হল রিপিট করা ক্যাপচার অনুরোধ এবং B হল সিঙ্গেল-ফ্রেম ক্যাপচার অনুরোধ। সেশন কীভাবে অনুরোধের সারি প্রসেস করে তা এখানে দেখানো হয়েছে:

ছবি ২. চলমান ক্যামেরা সেশনের জন্য অনুরোধের সারির ইলাস্ট্রেশন

অনুরোধ B অ্যাক্টিভেট হওয়ার আগে A থেকে শেষবার রিপিট করা অনুরোধ এবং A আবার ব্যবহার করার মধ্যে লেটেন্সি সম্পর্কে কোনও গ্যারান্টি নেই, তাই আপনি কিছু ফ্রেম বাদ পড়ার অভিজ্ঞতা পেতে পারেন। এই সমস্যা কমানোর জন্য আপনি কিছু জিনিস করতে পারেন:

  • অনুরোধ B-তে অনুরোধ A থেকে আউটপুট টার্গেট যোগ করুন। এইভাবে, খ-এর ফ্রেম রেডি হয়ে গেলে, সেটি ক-এর আউটপুট টার্গেটে কপি করা হয়। যেমন, স্থির ফ্রেম রেট বজায় রাখার জন্য ভিডিও স্ন্যাপশট নেওয়ার সময় এটি অপরিহার্য। আগের কোডে, অনুরোধ তৈরি করার আগে আপনি singleRequest.addTarget(previewSurface) যোগ করুন।

  • এই বিশেষ পরিস্থিতির জন্য কাজ করার উদ্দেশ্যে ডিজাইন করা টেমপ্লেটের একটি কম্বিনেশন ব্যবহার করুন, যেমন, জিরো-শাটার-ল্যাগ।