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

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

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

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

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

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

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

Feature 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
 }
}

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

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

  • การปรับปรุงกล้องพร้อมกัน: ด้วย CameraX 1.5.1 ตอนนี้คุณสามารถผูก Use Case ของการแสดงตัวอย่าง + การถ่ายภาพ + การบันทึกวิดีโอพร้อมกันสำหรับ SingleCameraConfig แต่ละรายการใน โหมดที่ไม่ใช่โหมดการจัดองค์ประกอบ นอกจากนี้ ในโหมดการจัดองค์ประกอบ (Use Case เดียวกันกับ 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 สำหรับ Camera Extensions

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

Camera-Compose เสถียรแล้ว

เรารู้ว่าคุณชื่นชอบ Jetpack Compose มากเพียงใด และยินดีที่จะประกาศให้ทราบว่าตอนนี้ camera-compose ไลบรารีเสถียรแล้วในเวอร์ชัน 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)

เริ่มวันนี้เลย

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

หากต้องการใช้ CameraX 1.5 โปรดเพิ่มทรัพยากร Dependency ต่อไปนี้ลงใน 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 หรือรายงานข้อบกพร่องได้ที่

เขียนโดย

อ่านต่อ