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

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

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

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

แผนภาพแนวคิดที่แสดงวิธีที่ CameraX จัดการ Use Case การจับภาพวิดีโอ
รูปที่ 2 แผนภาพแนวคิดที่แสดงวิธีที่ CameraX จัดการ Use Case VideoCapture

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

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

VideoCapture API จะแยกส่วนเครื่องมือการจับภาพที่ซับซ้อนและมอบ API ที่เรียบง่ายและตรงไปตรงมามากขึ้นให้แก่แอปพลิเคชัน

ภาพรวมของ VideoCapture API

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

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

  • VideoCapture คือคลาสกรณีการใช้งานระดับบนสุด VideoCapture จะเชื่อมโยงกับ LifecycleOwner ด้วย CameraSelector และ UseCase อื่นๆ ของ CameraX ดูข้อมูลเพิ่มเติมเกี่ยวกับแนวคิดและการใช้งานเหล่านี้ได้ที่สถาปัตยกรรม CameraX
  • Recorder คือการติดตั้งใช้งาน VideoOutput ที่เชื่อมต่อกับ VideoCapture อย่างแน่นหนา Recorder ใช้เพื่อจับภาพวิดีโอและเสียง แอปพลิเคชันจะสร้างการบันทึกจาก 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 เพื่อเริ่มบันทึก
  5. ใช้ pause()/resume()/stop() บนRecordingเพื่อควบคุมการบันทึก
  6. ตอบสนองต่อ VideoRecordEvents ภายใน Listener เหตุการณ์

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

การใช้ VideoCapture API

หากต้องการผสานรวม Use Case VideoCapture ของ CameraX เข้ากับแอป ให้ทำดังนี้

  1. ผูก VideoCapture
  2. เตรียมและกำหนดค่าการบันทึก
  3. เริ่มและควบคุมการบันทึกรันไทม์

ส่วนต่อไปนี้จะอธิบายสิ่งที่คุณทำได้ในแต่ละขั้นตอนเพื่อให้ได้เซสชันการบันทึกตั้งแต่ต้นจนจบ

เชื่อมโยง VideoCapture

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

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

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

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

  • Quality.UHD สำหรับวิดีโอขนาด 4K Ultra HD (2160p)
  • Quality.QHD สำหรับขนาดวิดีโอ Quad HD (1440p) ซึ่งเปิดตัวใน CameraX 1.7.0-alpha02
  • Quality.FHD สำหรับขนาดวิดีโอ Full HD (1080p)
  • Quality.HD สำหรับขนาดวิดีโอความละเอียดสูง (720p)
  • Quality.SD สำหรับขนาดวิดีโอ SD (480p)

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

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

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

  • ระบุความละเอียดที่ต้องการ 2-3 รายการโดยใช้ fromOrderedList() และรวมกลยุทธ์สำรองเพื่อใช้ในกรณีที่ไม่รองรับความละเอียดที่ต้องการ

    CameraX สามารถตัดสินใจเลือกรายการสำรองที่ตรงกันที่สุดตามความสามารถของกล้องที่เลือก โปรดดูรายละเอียดเพิ่มเติมที่ FallbackStrategy specification ของ QualitySelector ตัวอย่างเช่น โค้ดต่อไปนี้จะขอความละเอียดสูงสุดที่รองรับสำหรับการบันทึก และหากไม่รองรับความละเอียดที่ขอเลย ให้อนุญาต CameraX เลือกความละเอียดที่ใกล้เคียงกับความละเอียด Quality.SD มากที่สุด

    val qualitySelector = QualitySelector.fromOrderedList(
             listOf(Quality.UHD, Quality.QHD, 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.QHD, 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.QHD -> "QHD"
            Quality.FHD -> "FHD"
            Quality.HD -> "HD"
            Quality.SD -> "SD"
            else -> throw IllegalArgumentException()
        }
    }
    
    

    โปรดทราบว่าความสามารถที่แสดงผลจาก QualitySelector.getSupportedQualities() รับประกันว่าจะทำงานได้กับกรณีการใช้งาน VideoCapture หรือกรณีการใช้งาน VideoCapture และ Preview ร่วมกัน เมื่อเชื่อมโยงร่วมกับ Use Case 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() เพื่อลงทะเบียน Listener VideoRecordEvent และเริ่มจับภาพวิดีโอ

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>)
  • อนุญาตให้การบันทึกต่อเนื่องขณะที่ VideoCapture ที่แนบอยู่ถูกเชื่อมโยงกับกล้องอีกตัวด้วย 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);

ช่วงไดนามิก (วิดีโอ HDR)

CameraX รองรับการบันทึกวิดีโอ High Dynamic Range (HDR) 10 บิต เช่น HLG10, HDR10, HDR10+ หรือ Dolby Vision โดยใช้ DynamicRange

หากต้องการใช้การบันทึกวิดีโอ HDR ให้ทำตามขั้นตอนต่อไปนี้

  1. ค้นหาช่วงไดนามิกที่กล้องรองรับโดยใช้ VideoCapabilities.getSupportedDynamicRanges()
  2. ไม่บังคับ: หากคุณกำหนดค่า QualitySelector ที่กำหนดเอง ให้ตรวจสอบคุณภาพที่รองรับสำหรับช่วงไดนามิกนั้นโดยใช้ getSupportedQualities(DynamicRange)
  3. กำหนดค่า VideoCapture.Builder ด้วย setDynamicRange()

ตัวอย่างต่อไปนี้จะเปิดใช้การบันทึก HDR 10 บิตแบบ HLG เมื่อกล้องรองรับ

Kotlin

val videoCapabilities = Recorder.getVideoCapabilities(cameraInfo)
val supportedHdrRanges = videoCapabilities.supportedDynamicRanges
    .filter { it != DynamicRange.SDR }

val recorder = Recorder.Builder().build()
val videoCapture = VideoCapture.Builder(recorder)
    .apply {
        if (supportedHdrRanges.contains(DynamicRange.HLG_10_BIT)) {
            setDynamicRange(DynamicRange.HLG_10_BIT)
        }
    }
    .build()

Java

VideoCapabilities videoCapabilities = Recorder.getVideoCapabilities(cameraInfo);
Set<DynamicRange> supportedRanges = videoCapabilities.getSupportedDynamicRanges();

Recorder recorder = new Recorder.Builder().build();
VideoCapture.Builder<Recorder> builder = new VideoCapture.Builder<>(recorder);
if (supportedRanges.contains(DynamicRange.HLG_10_BIT)) {
    builder.setDynamicRange(DynamicRange.HLG_10_BIT);
}
VideoCapture<Recorder> videoCapture = builder.build();

การป้องกันภาพวิดีโอสั่นไหว

CameraX รองรับระบบกันสั่นของวิดีโอเพื่อลดการสั่นไหวและกระตุกเมื่อถือกล้องถ่ายวิดีโอด้วยมือ

หากต้องการเปิดใช้ระบบกันภาพสั่นไหวของวิดีโอ ให้ทำตามขั้นตอนต่อไปนี้

  1. ตรวจสอบว่าอุปกรณ์กล้องรองรับระบบกันสั่นหรือไม่โดยใช้ VideoCapabilities.isStabilizationSupported()
  2. เปิดใช้ใน VideoCapture.Builder โดยใช้ setVideoStabilizationEnabled(true)

ตัวอย่างต่อไปนี้จะเปิดใช้ระบบกันภาพสั่นเมื่อกล้องรองรับ

Kotlin

val videoCapabilities = Recorder.getVideoCapabilities(cameraInfo)
val videoCapture = VideoCapture.Builder(recorder)
    .setVideoStabilizationEnabled(videoCapabilities.isStabilizationSupported)
    .build()

Java

VideoCapabilities videoCapabilities = Recorder.getVideoCapabilities(cameraInfo);
VideoCapture<Recorder> videoCapture = new VideoCapture.Builder<>(recorder)
    .setVideoStabilizationEnabled(videoCapabilities.isStabilizationSupported())
    .build();

ควบคุมการบันทึกที่ทำงานอยู่

คุณหยุดชั่วคราว เล่นต่อ และหยุด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

แอมพลิจูดและสถานะของเสียงแบบเรียลไทม์

ในระหว่างการบันทึก เหตุการณ์ VideoRecordEvent.Status จะให้สถิติเสียงแบบเรียลไทม์ผ่าน AudioStats ดังนี้

  • AudioStats.getAudioAmplitude() จะแสดงแอมพลิจูดสูงสุดของเสียงในปัจจุบัน ซึ่งมีตั้งแต่ 0.0 ถึง 1.0 คุณสามารถใช้ค่านี้เพื่อขับเคลื่อนมิเตอร์ UI หรือเครื่องมือแสดงภาพรูปคลื่นเสียงได้
  • AudioStats.getAudioState() ระบุสถานะปัจจุบันของสตรีมเสียง เช่น AUDIO_STATE_ACTIVE, AUDIO_STATE_MUTED หรือ AUDIO_STATE_SOURCE_SILENCED

ตัวอย่างต่อไปนี้จะอ่านแอมพลิจูดของเสียงจากเหตุการณ์สถานะ

Kotlin

when (event) {
    is VideoRecordEvent.Status -> {
        val audioStats = event.recordingStats.audioStats
        if (audioStats.hasAudio()) {
            val amplitude = audioStats.audioAmplitude
            updateAudioWaveform(amplitude)
        }
    }
    // ...
}

Java

if (event instanceof VideoRecordEvent.Status) {
    VideoRecordEvent.Status status = (VideoRecordEvent.Status) event;
    AudioStats audioStats = status.getRecordingStats().getAudioStats();
    if (audioStats.hasAudio()) {
        double amplitude = audioStats.getAudioAmplitude();
        updateAudioWaveform(amplitude);
    }
}

วิดีโอความเร็วสูงและสโลว์โมชัน

CameraX รองรับการบันทึกวิดีโอความเร็วสูง เช่น 120, 240 หรือ 480 FPS ซึ่งช่วยให้ใช้งานได้ 2 กรณีที่แตกต่างกัน ดังนี้

  • วิดีโอที่มีอัตราเฟรมสูง (สโลว์โมชันที่จัดการโดยเพลเยอร์): CameraX จะจับภาพและบันทึกเฟรมที่อัตราเฟรมสูง (เช่น 120 FPS) วิดีโอเพลเยอร์จะควบคุมความเร็วในการเล่น ซึ่งช่วยให้ผู้ใช้สลับระหว่างความเร็วปกติกับสโลว์โมชันหรือทำการวิเคราะห์แบบเฟรมต่อเฟรมได้
  • วิดีโอสโลว์โมชันที่พร้อมเล่น: CameraX จะประมวลผลสตรีมความเร็วสูงและแสดงผลไฟล์วิดีโอมาตรฐาน 30 FPS พร้อมการประทับเวลาเฟรมที่ปรับแล้ว เอฟเฟกต์สโลว์โมชันจะ "ฝังอยู่" ในวิดีโอ ดังนั้นวิดีโอจะเล่นแบบสโลว์โมชันโดยอัตโนมัติในวิดีโอเพลเยอร์มาตรฐานโดยไม่ต้องใช้เพลเยอร์พิเศษ ตัวอย่างเช่น การจับภาพ 120 FPS ที่เล่นที่ 30 FPS จะสร้างวิดีโอสโลว์โมชัน 1/4 เท่า

ตรวจสอบความสามารถในการเชื่อมต่อความเร็วสูง

การจับภาพวิดีโอความเร็วสูงต้องใช้การรองรับฮาร์ดแวร์และคำจำกัดความ CamcorderProfile ที่เกี่ยวข้องจากผู้ผลิตอุปกรณ์ เช่น CamcorderProfile.QUALITY_HIGH_SPEED_1080P หรือ QUALITY_HIGH_SPEED_720P

ก่อนกำหนดค่าการบันทึกความเร็วสูง ให้ค้นหาความสามารถความเร็วสูงโดยใช้ Recorder.getHighSpeedVideoCapabilities(CameraInfo) ดังนี้

Kotlin

val highSpeedCapabilities = Recorder.getHighSpeedVideoCapabilities(cameraInfo)
if (highSpeedCapabilities == null) {
    // Camera does not support high-speed video capture
    return
}
val supportedQualities = highSpeedCapabilities.getSupportedQualities(DynamicRange.SDR)

Java

VideoCapabilities highSpeedCapabilities = Recorder.getHighSpeedVideoCapabilities(cameraInfo);
if (highSpeedCapabilities == null) {
    // Camera does not support high-speed video capture
    return;
}
List<Quality> supportedQualities = highSpeedCapabilities.getSupportedQualities(DynamicRange.SDR);

กำหนดค่า HighSpeedVideoSessionConfig

หากต้องการใช้การจับภาพความเร็วสูง ให้รวมกรณีการใช้งาน VideoCapture และ Preview ไว้ใน HighSpeedVideoSessionConfig หากต้องการกำหนดค่าเซสชัน ให้ทำตามขั้นตอนต่อไปนี้

  1. สร้างกรณีการใช้งาน VideoCapture และกรณีการใช้งาน Preview
  2. เริ่มต้น HighSpeedVideoSessionConfig.Builder ด้วยกรณีการใช้งาน VideoCapture และแนบ Preview
  3. ค้นหาช่วงอัตราเฟรมที่รองรับโดยใช้ CameraInfo.getSupportedFrameRateRanges(SessionConfig) และตั้งค่าช่วงที่เลือก
  4. เลือกระหว่างวิดีโอที่มีอัตราเฟรมสูงหรือวิดีโอสโลว์โมชันที่พร้อมเล่น โดยทำดังนี้
    • หากต้องการสร้างวิดีโอที่มีอัตราเฟรมสูง ให้ปล่อย setSlowMotionEnabled(false) ไว้ (ค่าเริ่มต้น)
    • หากต้องการสร้างวิดีโอสโลว์โมชันที่พร้อมเล่น ให้เรียกใช้ setSlowMotionEnabled(true)
  5. เชื่อมโยงการกำหนดค่าเซสชันโดยใช้ cameraProvider.bindToLifecycle()

ตัวอย่างต่อไปนี้จะกำหนดค่าและเชื่อมโยงเซสชันสโลว์โมชันที่พร้อมเล่น

Kotlin

val preview = Preview.Builder().build()
val recorder = Recorder.Builder()
    .setQualitySelector(QualitySelector.from(supportedQualities.first()))
    .build()
val videoCapture = VideoCapture.withOutput(recorder)

// Build HighSpeedVideoSessionConfig
val sessionConfigBuilder = HighSpeedVideoSessionConfig.Builder(videoCapture)
    .setPreview(preview)
    // Enable automatic slow-motion playback at 30 fps
    .setSlowMotionEnabled(true)

// Query and set a supported high-speed frame rate range (such as 120 or 240 fps).
// The set is non-empty because getHighSpeedVideoCapabilities() returned non-null earlier.
val supportedFpsRanges = cameraInfo.getSupportedFrameRateRanges(sessionConfigBuilder.build())
sessionConfigBuilder.setFrameRateRange(supportedFpsRanges.first())

val sessionConfig = sessionConfigBuilder.build()

// Bind session config to lifecycle
cameraProvider.bindToLifecycle(
    lifecycleOwner,
    CameraSelector.DEFAULT_BACK_CAMERA,
    sessionConfig
)

Java

Preview preview = new Preview.Builder().build();
Recorder recorder = new Recorder.Builder()
    .setQualitySelector(QualitySelector.from(supportedQualities.get(0)))
    .build();
VideoCapture<Recorder> videoCapture = VideoCapture.withOutput(recorder);

HighSpeedVideoSessionConfig.Builder sessionConfigBuilder =
    new HighSpeedVideoSessionConfig.Builder(videoCapture)
        .setPreview(preview)
        .setSlowMotionEnabled(true);

// The set is non-empty because getHighSpeedVideoCapabilities() returned non-null earlier.
Set<Range<Integer>> supportedFpsRanges =
    cameraInfo.getSupportedFrameRateRanges(sessionConfigBuilder.build());
sessionConfigBuilder.setFrameRateRange(supportedFpsRanges.iterator().next());

HighSpeedVideoSessionConfig sessionConfig = sessionConfigBuilder.build();

cameraProvider.bindToLifecycle(
    lifecycleOwner,
    CameraSelector.DEFAULT_BACK_CAMERA,
    sessionConfig
);

นอกจากนี้ คุณยังใช้ Kotlin DSL ซึ่งเปิดตัวใน CameraX 1.7.0-alpha02 เพื่อกำหนดค่าเซสชันความเร็วสูงอย่างกระชับได้ด้วย โดยทำดังนี้

val sessionConfig = highSpeedVideoSessionConfig(videoCapture) {
    this.preview = preview
    isSlowMotionEnabled = true
    frameRateRange = supportedFpsRanges.first()
}
cameraProvider.bindToLifecycle(
    lifecycleOwner,
    CameraSelector.DEFAULT_BACK_CAMERA,
    sessionConfig
)

บันทึกวิดีโอความเร็วสูงหรือสโลว์โมชัน

หลังจากเชื่อมต่อ HighSpeedVideoSessionConfig แล้ว ให้เริ่มบันทึกโดยใช้ VideoCapture ในลักษณะเดียวกับการบันทึกวิดีโอมาตรฐาน ดังนี้

Kotlin

val recording = videoCapture.output
    .prepareRecording(context, mediaStoreOutput)
    .withAudioEnabled()
    .start(ContextCompat.getMainExecutor(context)) { event ->
        when (event) {
            is VideoRecordEvent.Start -> Log.d(TAG, "Recording started")
            is VideoRecordEvent.Finalize -> {
                if (!event.hasError()) {
                    Log.d(TAG, "Video saved: ${event.outputResults.outputUri}")
                }
            }
        }
    }

Java

Recording recording = videoCapture.getOutput()
    .prepareRecording(context, mediaStoreOutput)
    .withAudioEnabled()
    .start(ContextCompat.getMainExecutor(context), event -> {
        if (event instanceof VideoRecordEvent.Start) {
            Log.d(TAG, "Recording started");
        } else if (event instanceof VideoRecordEvent.Finalize) {
            VideoRecordEvent.Finalize finalize = (VideoRecordEvent.Finalize) event;
            if (!finalize.hasError()) {
                Log.d(TAG, "Video saved: " + finalize.getOutputResults().getOutputUri());
            }
        }
    });

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

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