สถาปัตยกรรมการจับภาพวิดีโอของ CameraX

โดยทั่วไปแล้ว ระบบจับภาพจะบันทึกสตรีมวิดีโอและเสียงแล้วบีบอัด ปรับสตรีมทั้งสองรายการ จากนั้นเขียนสตรีมผลลัพธ์ไปยังดิสก์

วันที่ แผนภาพระบบบันทึกวิดีโอและเสียง
รูปที่ 1 แผนภาพตามแนวคิดสำหรับวิดีโอและเสียง ระบบบันทึกภาพ

ใน CameraX โซลูชันสำหรับการจับภาพวิดีโอคือ VideoCapture กรณีการใช้งาน:

วันที่ แผนภาพที่แสดงวิธีที่กล้อง x จัดการกับ
         กรณีการใช้งานการจับภาพวิดีโอ
รูปที่ 2 แผนภาพเชิงแนวคิดที่แสดงวิธีที่ CameraX จัดการ Use Case ของ VideoCapture

ดังแสดงในรูปที่ 2 การจับภาพวิดีโอจาก CameraX จะรวมภาพระดับสูง ส่วนประกอบทางสถาปัตยกรรม

  • SurfaceProvider สำหรับแหล่งที่มาของวิดีโอ
  • AudioSource สำหรับแหล่งที่มาของเสียง
  • โปรแกรมเปลี่ยนไฟล์ 2 โปรแกรมที่ใช้เข้ารหัสและบีบอัดวิดีโอ/เสียง
  • คนมักสื่อผสมสตรีมทั้ง 2 แบบ
  • ไฟล์รักษาไฟล์เพื่อเขียนผลลัพธ์ออกมา

VideoCapture API จะตัดเครื่องมือจับภาพที่ซับซ้อนและให้ ด้วย API ที่ใช้งานง่ายและเรียบง่ายมากๆ

ภาพรวม VideoCapture API

VideoCapture เป็นกรณีการใช้งานของ CameraX ที่ทำงานได้ดีทั้งในตัวแอปเองหรือเมื่อ รวมกับกรณีการใช้งานอื่นๆ ชุดค่าผสมที่รองรับเฉพาะขึ้นอยู่กับ ความสามารถของฮาร์ดแวร์กล้อง แต่ Preview และ VideoCapture Use Case ที่ถูกต้องร่วมกันในอุปกรณ์ทั้งหมด

VideoCapture API ประกอบด้วยออบเจ็กต์ต่อไปนี้ที่สื่อสาร ด้วยแอปพลิเคชัน

  • VideoCapture คือ Use Case ระดับบนสุด VideoCapture เชื่อมโยงกับ LifecycleOwner ที่มี CameraSelector และ CameraX อื่นๆ Use Case สำหรับข้อมูลเพิ่มเติมเกี่ยวกับแนวคิดและการใช้งานเหล่านี้ โปรดดู สถาปัตยกรรม CameraX
  • Recorder คือ การใช้งาน VideoOutput ที่เชื่อมกับ VideoCapture อย่างใกล้ชิด Recorder จะใช้ในการบันทึกวิดีโอและเสียง CANNOT TRANSLATE แอปพลิเคชันสร้างการบันทึกจาก Recorder
  • PendingRecording กำหนดค่าการบันทึก โดยมอบตัวเลือกต่างๆ เช่น เปิดใช้เสียงและการตั้งค่า Listener เหตุการณ์ คุณต้องใช้ Recorder เพื่อสร้าง PendingRecording PendingRecording จะไม่บันทึกข้อมูลใดๆ
  • Recording จะดำเนินการ บันทึกจริง คุณต้องใช้ PendingRecording เพื่อสร้าง Recording

รูปที่ 3 แสดงความสัมพันธ์ระหว่างวัตถุเหล่านี้

วันที่ แผนภาพแสดงการโต้ตอบที่เกิดขึ้นในวิดีโอ
         บันทึก Use Case
รูปที่ 3 แผนภาพแสดงการโต้ตอบที่เกิดขึ้น ใน Use Case ของ VideoCapture

คำอธิบาย:

  1. สร้าง Recorder ด้วย QualitySelector
  2. กำหนดค่า Recorder ด้วยหนึ่งใน OutputOptions
  3. เปิดใช้เสียงกับ withAudioEnabled() หากจำเป็น
  4. โทร start() กับ VideoRecordEvent Listener เพื่อเริ่มการบันทึก
  5. ใช้ pause()/resume()/stop() ใน Recording เพื่อควบคุมการบันทึก
  6. ตอบกลับ VideoRecordEvents ใน Listener เหตุการณ์

รายการ API โดยละเอียดอยู่ใน current.txt ในซอร์สโค้ด

การใช้ VideoCapture API

วิธีผสานรวมกรณีการใช้งาน VideoCapture ของ CameraX ในแอปของคุณ ให้ทำดังนี้

  1. เชื่อมโยง VideoCapture
  2. เตรียมและกำหนดค่าการบันทึก
  3. เริ่มต้นและควบคุมการบันทึกรันไทม์

ส่วนต่อไปนี้จะอธิบายถึงสิ่งที่คุณทำได้ในแต่ละขั้นตอน จากต้นทางถึงปลายทาง

เชื่อมโยง VideoCapture

ในการเชื่อมโยงกรณีการใช้งาน VideoCapure ให้ทำดังนี้

  1. สร้างออบเจ็กต์ Recorder
  2. สร้างออบเจ็กต์ VideoCapture
  3. เชื่อมโยงกับ Lifecycle

CameraX VideoCapture API เป็นไปตามรูปแบบการออกแบบของเครื่องมือสร้าง การสมัครงาน ใช้ Recorder.Builder เพื่อสร้าง Recorder นอกจากนี้ คุณยังกำหนดค่า ความละเอียดของวิดีโอสำหรับ Recorder ผ่านออบเจ็กต์ QualitySelector

CameraX Recorder รองรับ Qualities ที่กำหนดไว้ล่วงหน้าต่อไปนี้ สำหรับความละเอียดของวิดีโอ:

  • Quality.UHD สำหรับขนาดวิดีโอ 4K Ultra HD (2160p)
  • Quality.FHD สำหรับวิดีโอขนาด Full HD (1080p)
  • Quality.HD สำหรับขนาดวิดีโอ HD (720p)
  • Quality.SD สำหรับขนาดวิดีโอ SD (480p)

โปรดทราบว่า CameraX ยังสามารถเลือกความละเอียดอื่นๆ ได้เมื่อได้รับอนุญาตจากแอป

ขนาดวิดีโอที่แน่นอนของการเลือกแต่ละรายการจะขึ้นอยู่กับกล้องและโปรแกรมเปลี่ยนไฟล์ ความสามารถ สำหรับข้อมูลเพิ่มเติม โปรดดูเอกสารประกอบสำหรับ CamcorderProfile

แอปพลิเคชันสามารถกำหนดค่าความละเอียดได้โดยการสร้าง QualitySelector คุณสร้าง QualitySelector ได้โดยใช้วิธีใดวิธีหนึ่งต่อไปนี้

  • ระบุวิธีแก้ปัญหาที่ต้องการโดยใช้ fromOrderedList() และ รวมกลยุทธ์ทางเลือกไว้ใช้ในกรณีที่ไม่มี และรองรับความละเอียดที่ต้องการ

    CameraX สามารถเลือกการจับคู่วิดีโอสำรองที่ดีที่สุดได้โดยอิงจากกล้องที่เลือก โปรดดู FallbackStrategy specification ของ QualitySelector เพื่อดูรายละเอียดเพิ่มเติม ตัวอย่างเช่น โค้ดต่อไปนี้ร้องขอจำนวนสูงสุดที่รองรับ ในการบันทึก และหากไม่สามารถรองรับการแก้ปัญหาตามคำขอได้ อนุญาตให้ 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 หรือ การใช้ VideoCapture และ Preview ร่วมกัน เมื่อเชื่อมโยงกับ กรณีการใช้งาน 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. กำหนดค่า OutputOptions ด้วย prepareRecording()
  2. (ไม่บังคับ) เปิดใช้การบันทึกเสียง
  3. ใช้ start() เพื่อลงทะเบียน VideoRecordEvent Listener ของคุณ และเริ่มการบันทึกวิดีโอ

Recorder จะแสดงผลออบเจ็กต์ Recording เมื่อคุณเรียกใช้ฟังก์ชัน start() แอปพลิเคชันของคุณสามารถใช้ออบเจ็กต์ Recording นี้เพื่อสิ้นสุดการดำเนินการ เพื่อบันทึกหรือดำเนินการอื่นๆ เช่น หยุดชั่วคราวหรือกลับมาทำงานอีกครั้ง

Recorder รองรับออบเจ็กต์ Recording ครั้งละ 1 รายการ คุณสามารถเริ่ม การบันทึกใหม่เมื่อคุณโทรหา Recording.stop() หรือ Recording.close() ในออบเจ็กต์ Recording ก่อนหน้า

มาดูรายละเอียดเพิ่มเติมของขั้นตอนเหล่านี้กัน ประการแรก แอปพลิเคชันจะกำหนดค่า OutputOptions สำหรับโปรแกรมอัดเสียงกับ Recorder.prepareRecording() Recorder รองรับ OutputOptions ในประเภทต่อไปนี้

  • FileDescriptorOutputOptions เพื่อเก็บภาพไปยัง FileDescriptor
  • FileOutputOptionsสำหรับการจับภาพไปยัง File
  • MediaStoreOutputOptions เพื่อเก็บภาพไปยัง MediaStore

OutputOptions ทุกประเภทช่วยให้คุณตั้งค่าขนาดไฟล์สูงสุดด้วย setFileSizeLimit() ตัวเลือกอื่นๆ มีไว้สำหรับเอาต์พุตแต่ละรายการโดยเฉพาะ เช่น ParcelFileDescriptor สำหรับ FileDescriptorOutputOptions

prepareRecording() แสดงผลออบเจ็กต์ PendingRecording ซึ่งเป็น ออบเจ็กต์สื่อกลางที่ใช้เพื่อสร้าง ออบเจ็กต์ Recording รายการ PendingRecording เป็นคลาสชั่วคราวที่ควรจะเป็น มักจะมองไม่เห็นในกรณีส่วนใหญ่ และมักจะถูกแคชไว้ในแอปน้อย

แอปพลิเคชันอาจกำหนดค่าการบันทึกเพิ่มเติมได้ เช่น

  • เปิดใช้เสียงกับ withAudioEnabled()
  • ลงทะเบียน Listener เพื่อรับเหตุการณ์การบันทึกวิดีโอ ด้วย start(Executor, Consumer<VideoRecordEvent>)
  • อนุญาตให้มีการบันทึกอย่างต่อเนื่องในขณะที่วิดีโอจับภาพที่แนบอยู่ กลับไปที่กล้องตัวอื่นด้วย PendingRecording.asPersistentRecording()

โทร 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 เพื่อให้สามารถมิเรอร์การบันทึกวิดีโอ เพื่อให้การแสดงตัวอย่างของกล้องหน้าและ การจับคู่วิดีโอที่บันทึกไว้

ตัวเลือก MirrorMode มีอยู่ 3 แบบ ได้แก่ MIRROR_mode_OFF, MIRROR_mode_ON และ MIRROR_mode_ON_FRONT_ONLY เพื่อให้สอดคล้องกับ แสดงตัวอย่างจากกล้อง Google ขอแนะนำให้ใช้ MIROR_MODE_ON_FRONT_ONLY ซึ่งหมายความว่า นั่น ไม่ได้เปิดใช้มิเรอร์สำหรับกล้องหลัง แต่เปิดใช้สำหรับกล้องหน้า กล้อง ดูข้อมูลเพิ่มเติมเกี่ยวกับ MirrorMode ได้ที่ MirrorMode constants

ข้อมูลโค้ดนี้แสดงวิธีการเรียก VideoCapture.Builder.setMirrorMode() โดยใช้ MIRROR_MODE_ON_FRONT_ONLY สำหรับ ดูรายละเอียดเพิ่มเติมได้ที่ setMirrorMode()

Kotlin


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

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

useCases.add(videoCapture);

Java


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 ได้โดยไม่คำนึงถึง ว่าการบันทึกอยู่ในสถานะหยุดชั่วคราวหรือใช้งานอยู่หรือไม่

หากคุณลงทะเบียน EventListener กับ PendingRecording.start(), Recording สื่อสาร โดยใช้ VideoRecordEvent

  • VideoRecordEvent.EVENT_TYPE_STATUS จะใช้สำหรับการบันทึกสถิติเช่น ตามขนาดไฟล์ปัจจุบันและช่วงเวลาที่บันทึกไว้
  • มีการใช้ VideoRecordEvent.EVENT_TYPE_FINALIZE สำหรับผลการบันทึก และมีข้อมูล เช่น URI ของไฟล์สุดท้าย ข้อผิดพลาดที่เกี่ยวข้อง

เมื่อแอปของคุณได้รับ EVENT_TYPE_FINALIZE ซึ่งบ่งชี้ว่า แล้วเข้าถึงวิดีโอที่ถ่ายไว้จากตำแหน่งนั้นๆ ที่ระบุใน OutputOptions

แหล่งข้อมูลเพิ่มเติม

ดูข้อมูลเพิ่มเติมเกี่ยวกับ CameraX ได้ในแหล่งข้อมูลเพิ่มเติมต่อไปนี้