ข่าวสารผลิตภัณฑ์

ขอแนะนำ CameraX 1.5: การบันทึกวิดีโอที่ทรงพลังและการจับภาพระดับมือโปร

ใช้เวลาอ่าน 7 นาที
Scott Nien
วิศวกรซอฟต์แวร์

ทีม CameraX ยินดีที่จะประกาศการเปิดตัวเวอร์ชัน 1.5 การอัปเดตล่าสุดนี้มุ่งเน้นที่การนำความสามารถระดับมืออาชีพมาไว้ใกล้มือคุณ พร้อมทั้งทำให้การกำหนดค่าเซสชันกล้องง่ายกว่าที่เคย

สำหรับการบันทึกวิดีโอ ตอนนี้ผู้ใช้สามารถบันทึกวิดีโอสโลว์โมชันหรือวิดีโอที่มีอัตราเฟรมสูงได้อย่างง่ายดาย ที่สำคัญ Feature Group API ใหม่ช่วยให้คุณเปิดใช้การผสมผสานที่ซับซ้อนได้อย่างมั่นใจ เช่น HDR 10 บิตและ 60 FPS เพื่อให้มั่นใจว่าอุปกรณ์ที่รองรับจะให้ผลลัพธ์ที่สอดคล้องกัน

ในส่วนการจับภาพ คุณจะมีความยืดหยุ่นสูงสุดด้วยการรองรับการจับภาพไฟล์ DNG (RAW) ที่ไม่ได้ประมวลผลและไม่ได้บีบอัด นอกจากนี้ ตอนนี้คุณยังใช้ประโยชน์จากเอาต์พุต Ultra HDR ได้แม้จะใช้ส่วนขยายกล้องที่มีประสิทธิภาพก็ตาม

ฟีเจอร์เหล่านี้ทำงานด้วย SessionConfig API ใหม่ ซึ่งช่วยให้การตั้งค่าและกำหนดค่ากล้องใหม่เป็นไปอย่างราบรื่น ตอนนี้เรามาเจาะลึกรายละเอียดของฟีเจอร์ใหม่ๆ ที่น่าตื่นเต้นเหล่านี้กัน

การบันทึกวิดีโอที่มีประสิทธิภาพ: ความเร็วสูงและการรวมฟีเจอร์

CameraX 1.5 ขยายความสามารถด้านวิดีโออย่างมาก ทำให้บันทึกวิดีโอได้อย่างสร้างสรรค์และมีประสิทธิภาพมากขึ้น

วิดีโอสโลว์โมชันและวิดีโอที่มีอัตราเฟรมสูง

ฟีเจอร์วิดีโอสโลว์โมชันซึ่งเป็นหนึ่งในฟีเจอร์ที่เรารอคอยมากที่สุดพร้อมใช้งานแล้ว ตอนนี้คุณสามารถบันทึกวิดีโอความเร็วสูง (เช่น 120 หรือ 240 FPS) และเข้ารหัสเป็นวิดีโอสโลว์โมชันที่น่าตื่นตาตื่นใจได้โดยตรง หรือจะบันทึกที่อัตราเฟรมสูงเท่ากันเพื่อสร้างวิดีโอที่ราบรื่นเป็นพิเศษก็ได้

การใช้ API นี้เป็นเรื่องง่ายหากคุณคุ้นเคยกับ VideoCapture API

1. ตรวจสอบการรองรับความเร็วสูง: ใช้เมธอด Recorder.getHighSpeedVideoCapabilities() ใหม่เพื่อสอบถามว่าอุปกรณ์รองรับฟีเจอร์นี้หรือไม่

val cameraInfo = cameraProvider.getCameraInfo(cameraSelector)

val highSpeedCapabilities = Recorder.getHighSpeedVideoCapabilities(cameraInfo)

if (highSpeedCapabilities == null) {
    // This camera device does not support high-speed video.
    return
}

2. กำหนดค่าและเชื่อมโยงกรณีการใช้งาน: ใช้ videoCapabilities ที่ส่งคืน (ซึ่งมีข้อมูลคุณภาพวิดีโอที่รองรับ) เพื่อสร้าง HighSpeedVideoSessionConfig จากนั้นคุณต้องค้นหาช่วงอัตราเฟรมที่รองรับผ่าน cameraInfo.getSupportedFrameRateRanges() และตั้งค่าช่วงที่ต้องการ เรียกใช้ setSlowMotionEnabled(true) เพื่อบันทึกวิดีโอสโลว์โมชัน มิเช่นนั้นระบบจะบันทึกวิดีโอที่มีอัตราเฟรมสูง ขั้นตอนสุดท้ายคือการใช้ Recorder.prepareRecording().start() ปกติเพื่อเริ่มบันทึกวิดีโอ

val preview = Preview.Builder().build()
val quality = highSpeedCapabilities
        .getSupportedQualities(DynamicRange.SDR).first()

val recorder = Recorder.Builder()
      .setQualitySelector(QualitySelector.from(quality)))
      .build()

val videoCapture = VideoCapture.withOutput(recorder)

val frameRateRange = cameraInfo.getSupportedFrameRateRanges(      
       HighSpeedVideoSessionConfig(videoCapture, preview)
).first()

val sessionConfig = HighSpeedVideoSessionConfig(
    videoCapture, 
    preview, 
    frameRateRange = frameRateRange, 
    // Set true for slow-motion playback, or false for high-frame-rate
    isSlowMotionEnabled = true
)

cameraProvider.bindToLifecycle(
     lifecycleOwner, cameraSelector, sessionConfig)

// Start recording slow motion videos. 
val recording = recorder.prepareRecording(context, outputOption)
      .start(executor, {})

ความเข้ากันได้และข้อจำกัด

การบันทึกความเร็วสูงต้องรองรับ CameraConstrainedHighSpeedCaptureSession และ CamcorderProfile ที่เฉพาะเจาะจง ตรวจสอบความสามารถเสมอ และเปิดใช้การบันทึกความเร็วสูงเฉพาะในอุปกรณ์ที่รองรับเพื่อป้องกันไม่ให้ผู้ใช้ได้รับประสบการณ์ที่ไม่ดี ปัจจุบันฟีเจอร์นี้รองรับกล้องหลังของอุปกรณ์ Pixel เกือบทั้งหมดและบางรุ่นจากผู้ผลิตรายอื่นๆ

ดูรายละเอียดเพิ่มเติมได้ในบล็อกโพสต์

รวมฟีเจอร์อย่างมั่นใจ: Feature Group API

CameraX 1.5 เปิดตัว Feature Group API ซึ่งช่วยให้ไม่ต้องคาดเดาความเข้ากันได้ของฟีเจอร์ ตอนนี้คุณสามารถเปิดใช้ฟีเจอร์หลายอย่างพร้อมกันได้อย่างมั่นใจโดยอิงตามการค้นหาชุดค่าผสมของฟีเจอร์ API ของ Android 15 ซึ่งรับประกันเซสชันกล้องที่เสถียร ปัจจุบันกลุ่มฟีเจอร์รองรับ HDR (HLG), 60 FPS, การป้องกันภาพสั่นไหวแบบแสดงตัวอย่าง และ Ultra HDR เช่น คุณสามารถเปิดใช้ HDR, 60 FPS และการแสดงตัวอย่างการป้องกันภาพสั่นพร้อมกันใน Pixel 10 และ Galaxy S25 Series เราวางแผนที่จะปรับปรุงในอนาคตให้รวมถึงการบันทึกในระดับ 4K และการซูมแบบอัลตร้าไวด์ 

ฟีเจอร์ Group API ช่วยให้ใช้ Use Case ที่สำคัญ 2 อย่างได้ ดังนี้

กรณีการใช้งาน 1: จัดลำดับความสำคัญของคุณภาพที่ดีที่สุด

หากต้องการบันทึกโดยใช้ชุดฟีเจอร์ที่ดีที่สุดเท่าที่จะเป็นไปได้ คุณสามารถระบุรายการที่มีลำดับความสำคัญได้ CameraX จะพยายามเปิดใช้ฟีเจอร์เหล่านี้ตามลำดับ โดยเลือกชุดค่าผสมแรกที่อุปกรณ์รองรับอย่างเต็มที่

val sessionConfig = SessionConfig(
    useCases = listOf(preview, videoCapture),
    preferredFeatureGroup = listOf(
        GroupableFeature.HDR_HLG10,
        GroupableFeature.FPS_60,
        GroupableFeature.PREVIEW_STABILIZATION
    )
).apply {
    // (Optional) Get a callback with the enabled features to update your UI.
    setFeatureSelectionListener { selectedFeatures ->
        updateUiIndicators(selectedFeatures)
    }
}
processCameraProvider.bindToLifecycle(activity, cameraSelector, sessionConfig)

ในตัวอย่างนี้ CameraX จะพยายามเปิดใช้ฟีเจอร์ตามลำดับต่อไปนี้

  1. HDR + 60 FPS + การป้องกันภาพสั่นไหวในตัวอย่าง
  2. HDR + 60 FPS
  3. HDR + ระบบกันภาพสั่นแบบแสดงตัวอย่าง
  4. HDR
  5. 60 FPS + การป้องกันภาพสั่นไหวในตัวอย่าง
  6. 60 FPS
  7. แสดงตัวอย่างการกันภาพสั่น
  8. ไม่มี

กรณีการใช้งาน 2: สร้าง UI การตั้งค่าที่ผู้ใช้มองเห็น

ตอนนี้คุณสามารถแสดงให้เห็นอย่างถูกต้องว่าการผสมผสานฟีเจอร์ใดบ้างที่ UI การตั้งค่าของแอปคุณรองรับ โดยการปิดปุ่มเปิด/ปิดสำหรับตัวเลือกที่ไม่รองรับ เช่น รูปภาพด้านล่าง 

unsupported-features-disabled.gif

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

fun disableFeatureIfNotSuported(
   enabledFeatures: Set<GroupableFeature>,     
   featureToCheck:GroupableFeature
) {
 val sessionConfig = SessionConfig(
     useCases = useCases,
     requiredFeatureGroup = enabledFeatures + featureToCheck
 )
 val isSupported = cameraInfo.isFeatureGroupSupported(sessionConfig)

 if (!isSupported) {
     // disable the toggle for featureToCheck
 }
}

โปรดดูข้อมูลเพิ่มเติมในบล็อกโพสต์เกี่ยวกับกลุ่มฟีเจอร์  

การเพิ่มประสิทธิภาพวิดีโอเพิ่มเติม

  • การปรับปรุงกล้องพร้อมกัน: ตอนนี้คุณสามารถเชื่อมโยงกรณีการใช้งาน Preview + ImageCapture + VideoCapture พร้อมกันสำหรับ SingleCameraConfig แต่ละรายการใน non-composition mode ได้แล้วด้วย CameraX 1.5.1 นอกจากนี้ ในโหมดการคอมโพส (กรณีการใช้งานเดียวกันกับ CompositionSettings) ตอนนี้คุณสามารถตั้งค่า CameraEffect ที่ใช้กับผลลัพธ์การคอมโพสสุดท้ายได้แล้ว
  • การปิดเสียงแบบไดนามิก: ตอนนี้คุณเริ่มการบันทึกในสถานะปิดเสียงได้แล้วโดยใช้ PendingRecording.withAudioEnabled(boolean initialMuted) และอนุญาตให้ผู้ใช้เปิดเสียงในภายหลังได้โดยใช้ Recording.mute(boolean muted)
  • การจัดการพื้นที่เก็บข้อมูลไม่เพียงพอที่ได้รับการปรับปรุง: ตอนนี้ CameraX จะส่งข้อผิดพลาด VideoRecordEvent.Finalize.ERROR_INSUFFICIENT_STORAGE ได้อย่างน่าเชื่อถือแล้ว ซึ่งจะช่วยให้แอปของคุณจัดการสถานการณ์ที่มีพื้นที่เก็บข้อมูลเหลือน้อยและแจ้งให้ผู้ใช้ทราบได้อย่างราบรื่น
  • การเพิ่มคุณภาพในที่แสงน้อย: ในอุปกรณ์ที่รองรับ (เช่น ซีรีส์ Pixel 10) คุณสามารถเปิดใช้ CameraControl.enableLowLightBoostAsync เพื่อเพิ่มความสว่างให้กับสตรีมตัวอย่างและวิดีโอโดยอัตโนมัติในสภาพแวดล้อมที่มืด

การจับภาพระดับมืออาชีพ

CameraX 1.5 มาพร้อมการอัปเกรดครั้งใหญ่สำหรับ ImageCapture สำหรับนักพัฒนาแอปที่ต้องการคุณภาพและความยืดหยุ่นสูงสุด

ปลดปล่อยการควบคุมความคิดสร้างสรรค์ด้วยการจับภาพ DNG (RAW)

ตอนนี้ CameraX รองรับการจับภาพ DNG (RAW) แล้วเพื่อให้ควบคุมการประมวลผลภายหลังได้อย่างเต็มที่ ซึ่งจะช่วยให้คุณเข้าถึงข้อมูลรูปภาพที่ยังไม่ได้ประมวลผลและไม่ได้บีบอัดจากเซ็นเซอร์กล้องได้โดยตรง ทำให้สามารถแก้ไขและปรับสีในระดับมืออาชีพได้ API รองรับการบันทึกไฟล์ DNG เพียงอย่างเดียว หรือบันทึกเอาต์พุต JPEG และ DNG พร้อมกัน ดูโค้ดตัวอย่างด้านล่างเพื่อดูวิธีบันทึกไฟล์ JPEG และ DNG พร้อมกัน

val capabilities = ImageCapture.getImageCaptureCapabilities(cameraInfo)
val imageCapture = ImageCapture.Builder().apply {
    if (capabilities.supportedOutputFormats
             .contains(OUTPUT_FORMAT_RAW_JPEG)) {
        // Capture both RAW and JPEG formats.
        setOutputFormat(OUTPUT_FORMAT_RAW_JPEG)
    }
}.build()
// ... bind imageCapture to lifecycle ...


// Provide separate output options for each format.
val outputOptionRaw = /* ... configure for image/x-adobe-dng ... */
val outputOptionJpeg = /* ... configure for image/jpeg ... */
imageCapture.takePicture(
    outputOptionRaw,
    outputOptionJpeg,
    executor,
    object : ImageCapture.OnImageSavedCallback {
        override fun onImageSaved(results: OutputFileResults) {
            // This callback is invoked twice: once for the RAW file
            // and once for the JPEG file.
        }

        override fun onError(exception: ImageCaptureException) {}
    }
)

Ultra HDR สำหรับส่วนขยายกล้อง

รับสิ่งที่ดีที่สุดจากทั้ง 2 อย่าง นั่นคือการถ่ายภาพแบบดิจิทัลที่น่าทึ่งของส่วนขยายกล้อง (เช่น โหมดกลางคืน) ผสานรวมกับสีสันและช่วงไดนามิกที่ยอดเยี่ยมของ Ultra HDR ปัจจุบันฟีเจอร์นี้รองรับโทรศัพท์ Android ระดับพรีเมียมรุ่นล่าสุดหลายรุ่น เช่น ซีรีส์ Pixel 9/10 และซีรีส์ Samsung S24/S25

// Support UltraHDR when Extension is enabled. 

val extensionsEnabledCameraSelector = extensionsManager
     .getExtensionEnabledCameraSelector(
        CameraSelector.DEFAULT_BACK_CAMERA, ExtensionMode.NIGHT)

val imageCapabilities = ImageCapture.getImageCaptureCapabilities(
               cameraProvider.getCameraInfo(extensionsEnabledCameraSelector)

val imageCapture = ImageCapture.Builder()
     .apply {
       if (imageCapabilities.supportedOutputFormats
                .contains(OUTPUT_FORMAT_JPEG_ULTRA_HDR) {
           setOutputFormat(OUTPUT_FORMAT_JPEG_ULTRA_HDR)

       }

     }.build()

การปรับปรุง API หลักและความสามารถในการใช้งาน

วิธีกำหนดค่าแบบใหม่ SessionConfig

ดังที่เห็นในตัวอย่างด้านบน SessionConfig เป็นแนวคิดใหม่ใน CameraX 1.5 โดยจะรวมการกำหนดค่าไว้ที่ส่วนกลางและลดความซับซ้อนของ API ใน 2 วิธีหลักๆ ดังนี้

  1. ไม่ต้องเรียกใช้ด้วยตนเองอีกต่อไปunbind(): API ของ CameraX จะรับรู้ถึงวงจร ซึ่งจะ "ยกเลิกการเชื่อมโยง" กรณีการใช้งานโดยนัยเมื่อมีการทำลายกิจกรรมหรือ LifecycleOwner อื่นๆ แต่การอัปเดต Use Case หรือการเปลี่ยนกล้องยังคงต้องให้คุณโทรหา unbind() หรือ unbindAll() ก่อนที่จะผูกอีกครั้ง ตอนนี้เมื่อใช้ CameraX 1.5 เมื่อคุณเชื่อมโยง SessionConfig ใหม่ CameraX จะอัปเดตเซสชันให้คุณอย่างราบรื่นโดยไม่ต้องเรียกใช้การเลิกเชื่อมโยง
  2. การควบคุมอัตราเฟรมที่แน่นอน: SessionConfig API ใหม่จะแนะนำวิธีที่แน่นอนในการจัดการอัตราเฟรม setTargetFrameRate ก่อนหน้านี้เป็นเพียงคำแนะนำ แต่สำหรับวิธีใหม่นี้ รับประกัน ว่าระบบจะใช้ช่วงอัตราเฟรมที่ระบุเมื่อกำหนดค่าสำเร็จ คุณต้องค้นหาอัตราเฟรมที่รองรับโดยใช้ CameraInfo.getSupportedFrameRateRanges(SessionConfig) เพื่อให้แน่ใจว่ามีความแม่นยำ การส่ง SessionConfig แบบเต็มช่วยให้ CameraX กำหนดช่วงที่รองรับได้อย่างแม่นยำตามการกำหนดค่าสตรีม

Camera-Compose พร้อมใช้งานแล้ว

เราทราบดีว่าคุณชื่นชอบ Jetpack Compose มากเพียงใด และเรายินดีที่จะประกาศว่าตอนนี้camera-compose library มีความเสถียรแล้วในเวอร์ชัน 1.5.1 รุ่นนี้มีการแก้ไขข้อบกพร่องที่สำคัญซึ่งเกี่ยวข้องกับการใช้งาน CameraXViewfinder กับฟีเจอร์ Compose เช่น moveableContentOf และ Pager รวมถึงการแก้ไขปัญหาการยืดตัวอย่าง เราจะเพิ่มฟีเจอร์อื่นๆ ลงใน camera-compose ในรุ่นต่อๆ ไป

การปรับปรุง ImageAnalysis และ CameraControl

  • การปรับความแรงของไฟฉาย: ควบคุมไฟฉายของอุปกรณ์ได้อย่างละเอียดด้วย API ใหม่ คุณสามารถค้นหาความแรงสูงสุดที่รองรับได้โดยใช้ CameraInfo.getMaxTorchStrengthLevel() จากนั้นตั้งค่าระดับที่ต้องการด้วย CameraControl.setTorchStrengthLevel()
  • การรองรับ NV21 ใน ImageAnalysis: ตอนนี้คุณขอรูปแบบรูปภาพ NV21 ได้โดยตรงจาก ImageAnalysis ซึ่งช่วยให้การผสานรวมกับไลบรารีและ API อื่นๆ ง่ายขึ้น โดยจะเปิดใช้ได้ด้วยการเรียกใช้ ImageAnalysis.Builder.setOutputImageFormat(OUTPUT_IMAGE_FORMAT_NV21)

เริ่มต้นใช้งานวันนี้

อัปเดตการอ้างอิงเป็น CameraX 1.5 ได้เลย แล้วมาสำรวจฟีเจอร์ใหม่ๆ ที่น่าตื่นเต้นกัน เราจะตั้งตารอดูผลงานของคุณ

หากต้องการใช้ CameraX 1.5 โปรดเพิ่มการขึ้นต่อกันต่อไปนี้ลงใน libs.versions.toml (เราขอแนะนำให้ใช้เวอร์ชัน 1.5.1 ซึ่งมีการแก้ไขข้อบกพร่องที่สำคัญหลายอย่างและปรับปรุงกล้องให้ทำงานพร้อมกันได้) 

[versions]

camerax = "1.5.1"


[libraries]

..

androidx-camera-core = { module = "androidx.camera:camera-core", version.ref = "camerax" }

androidx-camera-compose = { module = "androidx.camera:camera-compose", version.ref = "camerax" }

androidx-camera-view = { module = "androidx.camera:camera-view", version.ref = "camerax" }

androidx-camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycle", version.ref = "camerax" }

androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "camerax" }

androidx-camera-extensions = { module = "androidx.camera:camera-extensions", version.ref = "camerax" }

จากนั้นเพิ่มโค้ดต่อไปนี้ลงในทรัพยากร Dependency ของ build.gradle.kts ของโมดูล

dependencies {

  ..

  implementation(libs.androidx.camera.core)
  implementation(libs.androidx.camera.lifecycle)

  implementation(libs.androidx.camera.camera2)

  implementation(libs.androidx.camera.view) // for PreviewView 
  implementation(libs.androidx.camera.compose) // for compose UI

  implementation(libs.androidx.camera.extensions) // For Extensions 

}

หากมีคำถามหรือต้องการติดต่อทีม CameraX เข้าร่วมกลุ่มสนทนาสำหรับนักพัฒนาแอป CameraX หรือส่งรายงานข้อบกพร่อง

เขียนโดย

อ่านต่อ