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

ขอแนะนำ 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) และเข้ารหัสเป็นวิดีโอสโลว์โมชันที่น่าทึ่งได้โดยตรง หรือจะบันทึกที่อัตราเฟรมสูงเท่ากันเพื่อสร้างวิดีโอที่ราบรื่นเป็นพิเศษก็ได้

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

ฟีเจอร์ Group API ช่วยให้ใช้ 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 Series) คุณสามารถเปิดใช้ 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 หรือส่งรายงานข้อบกพร่อง

เขียนโดย

อ่านต่อ