ক্যামেরাএক্স ভিডিও ক্যাপচারিং আর্কিটেকচার

একটি ক্যাপচারিং সিস্টেম সাধারণত ভিডিও এবং অডিও স্ট্রিম রেকর্ড করে, সেগুলোকে কম্প্রেস করে, দুটি স্ট্রিমকে মাক্স করে এবং তারপর চূড়ান্ত স্ট্রিমটি ডিস্কে লিখে দেয়।

ভিডিও এবং অডিও ক্যাপচারিং সিস্টেমের জন্য একটি ধারণাগত চিত্র
চিত্র ১. একটি ভিডিও ও অডিও ধারণকারী সিস্টেমের ধারণাগত চিত্র।

CameraX-এ, ভিডিও ক্যাপচার করার সমাধান হলো VideoCapture use case:

একটি ধারণামূলক চিত্র যা দেখায় কিভাবে ক্যামেরা x ভিডিও ক্যাপচার ব্যবহারের ক্ষেত্রটি পরিচালনা করে।
চিত্র ২. একটি ধারণামূলক চিত্র যা দেখায় কিভাবে CameraX VideoCapture ব্যবহার ক্ষেত্রটি পরিচালনা করে।

চিত্র ২-এ যেমন দেখানো হয়েছে, CameraX ভিডিও ক্যাপচারে কয়েকটি উচ্চ-স্তরের স্থাপত্যগত উপাদান অন্তর্ভুক্ত রয়েছে:

  • ভিডিও উৎসের জন্য SurfaceProvider
  • অডিও সোর্সের জন্য AudioSource
  • ভিডিও/অডিও এনকোড এবং কম্প্রেস করার জন্য দুটি এনকোডার।
  • দুটি স্ট্রিমকে মাক্স করার জন্য একটি মিডিয়া মাক্সার।
  • ফলাফল লিখে রাখার জন্য একটি ফাইল সেভার।

VideoCapture API জটিল ক্যাপচারিং ইঞ্জিনকে আড়াল করে এবং অ্যাপ্লিকেশনগুলোকে অনেক বেশি সরল ও সহজবোধ্য একটি API প্রদান করে।

ভিডিওক্যাপচার এপিআই ওভারভিউ

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

VideoCapture API নিম্নলিখিত অবজেক্টগুলো নিয়ে গঠিত, যেগুলো অ্যাপ্লিকেশনগুলোর সাথে যোগাযোগ করে:

  • VideoCapture হলো শীর্ষ-স্তরের ইউজ কেস ক্লাস। VideoCapture একটি CameraSelector এবং অন্যান্য CameraX UseCases সহ একটি LifecycleOwner সাথে বাইন্ড হয়। এই ধারণা এবং ব্যবহার সম্পর্কে আরও তথ্যের জন্য, CameraX Architecture দেখুন।
  • Recorder হলো ভিডিওআউটপুট-এর একটি বাস্তবায়ন যা VideoCapture সাথে নিবিড়ভাবে সংযুক্ত। ভিডিও এবং অডিও ধারণ করার জন্য Recorder ব্যবহৃত হয়। একটি অ্যাপ্লিকেশন Recorder থেকে রেকর্ডিং তৈরি করে
  • একটি PendingRecording একটি রেকর্ডিং কনফিগার করে, যা অডিও চালু করা এবং ইভেন্ট লিসেনার সেট করার মতো বিকল্প প্রদান করে। একটি PendingRecording তৈরি করতে আপনাকে অবশ্যই একটি Recorder ব্যবহার করতে হবে। একটি PendingRecording কিছুই রেকর্ড করে না।
  • একটি Recording প্রকৃত রেকর্ডিং সম্পন্ন করে। একটি Recording তৈরি করতে আপনাকে অবশ্যই একটি PendingRecording ব্যবহার করতে হবে।

চিত্র ৩-এ এই বস্তুগুলোর মধ্যকার সম্পর্ক দেখানো হয়েছে:

ভিডিও ক্যাপচার ইউজ কেসে যে ইন্টারঅ্যাকশনগুলো ঘটে তা দেখানো ডায়াগ্রাম
চিত্র ৩. একটি ভিডিওক্যাপচার ব্যবহারের ক্ষেত্রে সংঘটিত মিথস্ক্রিয়াগুলো দেখানো ডায়াগ্রাম।

কিংবদন্তি:

  1. QualitySelector ব্যবহার করে একটি Recorder তৈরি করুন।
  2. OutputOptions মধ্যে একটি দিয়ে Recorder কনফিগার করুন।
  3. প্রয়োজনে withAudioEnabled() ব্যবহার করে অডিও চালু করুন।
  4. রেকর্ডিং শুরু করতে একটি VideoRecordEvent লিসেনার সহ start() কল করুন।
  5. রেকর্ডিং নিয়ন্ত্রণ করতে Recording -এর উপর pause() / resume() / stop() ব্যবহার করুন।
  6. আপনার ইভেন্ট লিসেনারের ভিতরে VideoRecordEvents এ সাড়া দিন।

বিস্তারিত API তালিকাটি সোর্স কোডের ভিতরে থাকা current.txt ফাইলে রয়েছে।

VideoCapture API ব্যবহার করে

আপনার অ্যাপে CameraX VideoCapture ব্যবহারের ক্ষেত্রটি অন্তর্ভুক্ত করতে, নিম্নলিখিতগুলি করুন:

  1. VideoCapture সংযুক্ত করুন।
  2. রেকর্ডিং প্রস্তুত ও কনফিগার করুন।
  3. রানটাইম রেকর্ডিং শুরু ও নিয়ন্ত্রণ করুন।

একটি সম্পূর্ণ রেকর্ডিং সেশন সম্পন্ন করার জন্য প্রতিটি ধাপে আপনি কী করতে পারেন, তা নিম্নলিখিত বিভাগগুলিতে বর্ণনা করা হয়েছে।

ভিডিওক্যাপচার বাইন্ড করুন

VideoCapture ব্যবহারের ক্ষেত্রটি সংযুক্ত করতে, নিম্নলিখিতগুলি করুন:

  1. একটি Recorder অবজেক্ট তৈরি করুন।
  2. VideoCapture অবজেক্ট তৈরি করুন।
  3. একটি Lifecycle সাথে সংযুক্ত করুন।

CameraX VideoCapture API বিল্ডার ডিজাইন প্যাটার্ন অনুসরণ করে। অ্যাপ্লিকেশনগুলো একটি Recorder তৈরি করতে Recorder.Builder ব্যবহার করে। এছাড়াও, আপনি একটি QualitySelector অবজেক্টের মাধ্যমে Recorder টির জন্য ভিডিও রেজোলিউশন কনফিগার করতে পারেন।

CameraX Recorder ভিডিও রেজোলিউশনের জন্য নিম্নলিখিত পূর্ব-নির্ধারিত Qualities সমর্থন করে:

  • Quality.UHD (4K আল্ট্রা এইচডি ভিডিও সাইজ বা 2160p)-এর জন্য)
  • ফুল এইচডি ভিডিও সাইজের (1080p) জন্য Quality.FHD
  • এইচডি ভিডিও সাইজের (৭২০পি) জন্য Quality.HD
  • SD ভিডিও সাইজের (480p) জন্য Quality.SD

উল্লেখ্য যে, অ্যাপের অনুমতি সাপেক্ষে CameraX অন্যান্য রেজোলিউশনও বেছে নিতে পারে।

প্রতিটি নির্বাচনের সঠিক ভিডিও আকার ক্যামেরা এবং এনকোডারের সক্ষমতার উপর নির্ভর করে। আরও তথ্যের জন্য, CamcorderProfile এর ডকুমেন্টেশন দেখুন।

অ্যাপ্লিকেশনগুলো একটি QualitySelector তৈরি করার মাধ্যমে রেজোলিউশন কনফিগার করতে পারে। আপনি নিম্নলিখিত পদ্ধতিগুলোর যেকোনো একটি ব্যবহার করে একটি QualitySelector তৈরি করতে পারেন:

  • fromOrderedList() ব্যবহার করে কয়েকটি পছন্দের সমাধান প্রদান করুন, এবং পছন্দের কোনো সমাধানই সমর্থিত না হলে ব্যবহারের জন্য একটি ফলব্যাক কৌশল অন্তর্ভুক্ত করুন।

    CameraX নির্বাচিত ক্যামেরার সক্ষমতার উপর ভিত্তি করে সেরা ফলব্যাক ম্যাচটি নির্ধারণ করতে পারে, আরও বিস্তারিত জানার জন্য QualitySelector এর FallbackStrategy specification দেখুন। উদাহরণস্বরূপ, নিম্নলিখিত কোডটি রেকর্ডিংয়ের জন্য সর্বোচ্চ সমর্থিত রেজোলিউশনের অনুরোধ করে, এবং যদি অনুরোধ করা কোনো রেজোলিউশনই সমর্থন করা না যায়, তবে CameraX-কে Quality.SD রেজোলিউশনের সবচেয়ে কাছাকাছি একটি রেজোলিউশন বেছে নেওয়ার অনুমোদন দেয়:

    val qualitySelector = QualitySelector.fromOrderedList(
             listOf(Quality.UHD, Quality.FHD, Quality.HD, Quality.SD),
             FallbackStrategy.lowerQualityOrHigherThan(Quality.SD))
    
  • প্রথমে ক্যামেরার সক্ষমতা সম্পর্কে জিজ্ঞাসা করুন, এবং QualitySelector::from() ব্যবহার করে সমর্থিত রেজোলিউশনগুলো থেকে বেছে নিন।

    val cameraInfo = cameraProvider.availableCameraInfos.filter {
        Camera2CameraInfo
        .from(it)
        .getCameraCharacteristic(CameraCharacteristics.LENS\_FACING) == CameraMetadata.LENS_FACING_BACK
    }
    
    val supportedQualities = QualitySelector.getSupportedQualities(cameraInfo[0])
    val filteredQualities = arrayListOf (Quality.UHD, Quality.FHD, Quality.HD, Quality.SD)
                           .filter { supportedQualities.contains(it) }
    
    // Use a simple ListView with the id of simple_quality_list_view
    viewBinding.simpleQualityListView.apply {
        adapter = ArrayAdapter(context,
                               android.R.layout.simple_list_item_1,
                               filteredQualities.map { it.qualityToString() })
    
        // Set up the user interaction to manually show or hide the system UI.
        setOnItemClickListener { _, _, position, _ ->
            // Inside View.OnClickListener,
            // convert Quality.* constant to QualitySelector
            val qualitySelector = QualitySelector.from(filteredQualities[position])
    
            // Create a new Recorder/VideoCapture for the new quality
            // and bind to lifecycle
            val recorder = Recorder.Builder()
                .setQualitySelector(qualitySelector).build()
    
             // ...
        }
    }
    
    // A helper function to translate Quality to a string
    fun Quality.qualityToString() : String {
        return when (this) {
            Quality.UHD -> "UHD"
            Quality.FHD -> "FHD"
            Quality.HD -> "HD"
            Quality.SD -> "SD"
            else -> throw IllegalArgumentException()
        }
    }
    
    

    উল্লেখ্য যে, QualitySelector.getSupportedQualities() থেকে প্রাপ্ত সক্ষমতাটি VideoCapture ব্যবহারের ক্ষেত্র অথবা VideoCapturePreview ব্যবহারের ক্ষেত্রের সমন্বয়ের জন্য কাজ করার নিশ্চয়তা দেয়। ImageCapture বা ImageAnalysis ব্যবহারের ক্ষেত্রের সাথে একত্রে বাইন্ডিং করার সময়, অনুরোধ করা ক্যামেরায় প্রয়োজনীয় সমন্বয়টি সমর্থিত না হলে CameraX বাইন্ডিংটি ব্যর্থ করে দিতে পারে।

একবার আপনার কাছে একটি QualitySelector থাকলে, অ্যাপ্লিকেশনটি একটি VideoCapture অবজেক্ট তৈরি করতে এবং বাইন্ডিং সম্পাদন করতে পারে। মনে রাখবেন যে এই বাইন্ডিংটি অন্যান্য ব্যবহারের ক্ষেত্রের মতোই:

val recorder = Recorder.Builder()
    .setExecutor(cameraExecutor).setQualitySelector(qualitySelector)
    .build()
val videoCapture = VideoCapture.withOutput(recorder)

try {
    // Bind use cases to camera
    cameraProvider.bindToLifecycle(
            this, CameraSelector.DEFAULT_BACK_CAMERA, preview, videoCapture)
} catch(exc: Exception) {
    Log.e(TAG, "Use case binding failed", exc)
}

উল্লেখ্য যে, bindToLifecycle() একটি Camera অবজেক্ট রিটার্ন করে। জুম এবং এক্সপোজারের মতো ক্যামেরার আউটপুট নিয়ন্ত্রণ সম্পর্কে আরও তথ্যের জন্য এই নির্দেশিকাটি দেখুন।

Recorder সিস্টেমের জন্য সবচেয়ে উপযুক্ত ফরম্যাট নির্বাচন করে। সবচেয়ে প্রচলিত ভিডিও কোডেক হলো H.264 AVC এবং এর কন্টেইনার ফরম্যাট হলো MPEG-4

রেকর্ডিং কনফিগার এবং তৈরি করুন

একটি Recorder থেকে, অ্যাপ্লিকেশনটি ভিডিও এবং অডিও ধারণ করার জন্য রেকর্ডিং অবজেক্ট তৈরি করতে পারে। অ্যাপ্লিকেশনগুলো নিম্নলিখিত কাজগুলো করে রেকর্ডিং তৈরি করে:

  1. prepareRecording() এর সাথে OutputOptions কনফিগার করুন।
  2. (ঐচ্ছিক) অডিও রেকর্ডিং চালু করুন।
  3. একটি VideoRecordEvent লিসেনার রেজিস্টার করতে এবং ভিডিও ক্যাপচার শুরু করতে start() ব্যবহার করুন।

আপনি যখন start() ফাংশনটি কল করেন, তখন Recorder একটি Recording অবজেক্ট রিটার্ন করে। আপনার অ্যাপ্লিকেশন এই Recording অবজেক্টটি ব্যবহার করে ক্যাপচারিং শেষ করতে পারে অথবা পজ বা রিজুম করার মতো অন্যান্য কাজ সম্পাদন করতে পারে।

একটি Recorder একবারে একটিমাত্র Recording অবজেক্ট সমর্থন করে। পূর্ববর্তী Recording অবজেক্টে Recording.stop() বা Recording.close() কল করার পরেই আপনি একটি নতুন রেকর্ডিং শুরু করতে পারেন।

চলুন এই ধাপগুলো আরও বিস্তারিতভাবে দেখি। প্রথমে, অ্যাপ্লিকেশনটি Recorder.prepareRecording() ব্যবহার করে একটি Recorder-এর জন্য OutputOptions কনফিগার করে। একটি Recorder নিম্নলিখিত ধরনের OutputOptions সমর্থন করে:

  • একটি FileDescriptor এ ক্যাপচার করার জন্য FileDescriptorOutputOptions
  • File ক্যাপচার করার জন্য FileOutputOptions
  • MediaStore ক্যাপচার করার জন্য MediaStoreOutputOptions

সকল OutputOptions টাইপ আপনাকে setFileSizeLimit() ব্যবহার করে ফাইলের সর্বোচ্চ আকার নির্ধারণ করার সুযোগ দেয়। অন্যান্য অপশনগুলো নির্দিষ্ট আউটপুট টাইপের জন্য প্রযোজ্য, যেমন FileDescriptorOutputOptions এর জন্য ParcelFileDescriptor

prepareRecording() একটি PendingRecording অবজেক্ট রিটার্ন করে, যা একটি মধ্যবর্তী অবজেক্ট এবং এটি সংশ্লিষ্ট Recording অবজেক্টটি তৈরি করতে ব্যবহৃত হয়। PendingRecording একটি ক্ষণস্থায়ী ক্লাস যা বেশিরভাগ ক্ষেত্রে অদৃশ্য থাকে এবং অ্যাপ দ্বারা খুব কমই ক্যাশ করা হয়।

অ্যাপ্লিকেশনগুলি রেকর্ডিং আরও কনফিগার করতে পারে, যেমন:

  • withAudioEnabled() ব্যবহার করে অডিও চালু করুন।
  • start(Executor, Consumer<VideoRecordEvent>) ব্যবহার করে ভিডিও রেকর্ডিং ইভেন্ট গ্রহণ করার জন্য একটি লিসেনার নিবন্ধন করুন।
  • PendingRecording.asPersistentRecording() ব্যবহার করে, যে VideoCapture-এর সাথে এটি সংযুক্ত আছে সেটিকে অন্য একটি ক্যামেরার সাথে রিবাউন্ড করার সময়েও রেকর্ডিংটি অবিচ্ছিন্নভাবে চলতে দিন।

রেকর্ডিং শুরু করতে, PendingRecording.start() কল করুন। CameraX, PendingRecording কে একটি Recording এ রূপান্তরিত করে, রেকর্ডিং অনুরোধটি কিউতে রাখে এবং নতুন তৈরি হওয়া Recording অবজেক্টটি অ্যাপ্লিকেশনে ফেরত পাঠায়। সংশ্লিষ্ট ক্যামেরা ডিভাইসে রেকর্ডিং শুরু হয়ে গেলে, CameraX একটি VideoRecordEvent.EVENT_TYPE_START ইভেন্ট পাঠায়।

নিচের উদাহরণটিতে দেখানো হয়েছে কীভাবে একটি MediaStore ফাইলে ভিডিও এবং অডিও রেকর্ড করতে হয়:

// Create MediaStoreOutputOptions for our recorder
val name = "CameraX-recording-" +
        SimpleDateFormat(FILENAME_FORMAT, Locale.US)
                .format(System.currentTimeMillis()) + ".mp4"
val contentValues = ContentValues().apply {
   put(MediaStore.Video.Media.DISPLAY_NAME, name)
}
val mediaStoreOutput = MediaStoreOutputOptions.Builder(this.contentResolver,
                              MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
                              .setContentValues(contentValues)
                              .build()

// 2. Configure Recorder and Start recording to the mediaStoreOutput.
val recording = videoCapture.output
                .prepareRecording(context, mediaStoreOutput)
                .withAudioEnabled()
                .start(ContextCompat.getMainExecutor(this), captureListener)

ডিফল্টভাবে ফ্রন্ট ক্যামেরায় ক্যামেরা প্রিভিউ মিরর করা হলেও, VideoCapture দিয়ে রেকর্ড করা ভিডিও ডিফল্টভাবে মিরর হয় না। CameraX 1.3-এর মাধ্যমে এখন ভিডিও রেকর্ডিং মিরর করা সম্ভব, যাতে ফ্রন্ট ক্যামেরার প্রিভিউ এবং রেকর্ড করা ভিডিও মিলে যায়।

তিনটি মিররমোড অপশন আছে: MIRROR_MODE_OFF, MIRROR_MODE_ON, এবং MIRROR_MODE_ON_FRONT_ONLY। ক্যামেরা প্রিভিউয়ের সাথে অ্যালাইন করার জন্য, গুগল MIROR_MODE_ON_FRONT_ONLY ব্যবহার করার পরামর্শ দেয়, যার অর্থ হলো পেছনের ক্যামেরার জন্য মিররিং চালু থাকে না, কিন্তু সামনের ক্যামেরার জন্য চালু থাকে। মিররমোড সম্পর্কে আরও তথ্যের জন্য, MirrorMode constants দেখুন।

এই কোড স্নিপেটটি দেখায় কিভাবে MIRROR_MODE_ON_FRONT_ONLY ব্যবহার করে VideoCapture.Builder.setMirrorMode() কল করতে হয়। আরও তথ্যের জন্য, setMirrorMode() দেখুন।

কোটলিন

val recorder = Recorder.Builder().build()

val videoCapture = VideoCapture.Builder(recorder)
    .setMirrorMode(MIRROR_MODE_ON_FRONT_ONLY)
    .build()

useCases.add(videoCapture);

জাভা

Recorder.Builder builder = new Recorder.Builder();
if (mVideoQuality != QUALITY_AUTO) {
    builder.setQualitySelector(
        QualitySelector.from(mVideoQuality));
}
  VideoCapture<Recorder> videoCapture = new VideoCapture.Builder<>(builder.build())
      .setMirrorMode(MIRROR_MODE_ON_FRONT_ONLY)
      .build();
    useCases.add(videoCapture);

একটি সক্রিয় রেকর্ডিং নিয়ন্ত্রণ করুন

নিম্নলিখিত পদ্ধতিগুলো ব্যবহার করে আপনি একটি চলমান Recording পজ, রিজুম এবং স্টপ করতে পারেন:

  • বর্তমান সক্রিয় রেকর্ডিংটি থামাতে pause
  • বিরতি দেওয়া সক্রিয় রেকর্ডিং পুনরায় শুরু করতে resume() করুন।
  • রেকর্ডিং শেষ করতে এবং সংশ্লিষ্ট রেকর্ডিং অবজেক্টগুলো ফ্লাশ করতে stop() ব্যবহার করুন।
  • বর্তমান রেকর্ডিংটি মিউট বা আন-মিউট করতে mute() করুন।

মনে রাখবেন যে, রেকর্ডিংটি পজ করা বা সক্রিয় যে অবস্থাতেই থাকুক না কেন, আপনি stop() কল করে Recording বন্ধ করতে পারেন।

আপনি যদি PendingRecording.start() এর সাথে একটি EventListener রেজিস্টার করে থাকেন, তাহলে Recording একটি VideoRecordEvent ব্যবহার করে যোগাযোগ করে।

  • VideoRecordEvent.EVENT_TYPE_STATUS বর্তমান ফাইলের আকার এবং রেকর্ডকৃত সময়কালের মতো পরিসংখ্যান রেকর্ড করার জন্য ব্যবহৃত হয়।
  • VideoRecordEvent.EVENT_TYPE_FINALIZE রেকর্ডিংয়ের ফলাফলের জন্য ব্যবহৃত হয় এবং এতে চূড়ান্ত ফাইলের URI ও সংশ্লিষ্ট যেকোনো ত্রুটির মতো তথ্য অন্তর্ভুক্ত থাকে।

আপনার অ্যাপ যখন একটি সফল রেকর্ডিং সেশন নির্দেশকারী EVENT_TYPE_FINALIZE বার্তা পাবে, তখন আপনি OutputOptions এ নির্দিষ্ট করা অবস্থান থেকে ধারণ করা ভিডিওটি অ্যাক্সেস করতে পারবেন।

অতিরিক্ত সম্পদ

CameraX সম্পর্কে আরও জানতে, নিম্নলিখিত অতিরিক্ত উৎসগুলো দেখুন: