หมายเหตุ: หน้านี้เกี่ยวข้องกับแพ็กเกจ camera2 เราขอแนะนำให้ใช้ CameraX เว้นแต่แอปของคุณต้องใช้ฟีเจอร์ระดับต่ำที่เฉพาะเจาะจงจาก Camera2 ทั้ง CameraX และ Camera2 รองรับ Android 5.0 (API ระดับ 21) ขึ้นไป
อุปกรณ์ที่ใช้ระบบ Android เครื่องเดียวสามารถมีกล้องได้หลายตัว กล้องแต่ละตัว
CameraDevice
และ CameraDevice
จะแสดงสตรีม
มากกว่า 1 รายการพร้อมกันได้
เหตุผลหนึ่งที่ทำเช่นนี้ก็เพื่อให้สตรีม เฟรมกล้องตามลำดับ
จาก CameraDevice
ได้รับการปรับให้เหมาะกับงานที่เจาะจง เช่น การแสดง
ช่องมองภาพ ในขณะที่ส่วนอื่นๆ อาจใช้เพื่อถ่ายภาพหรือสร้างวิดีโอ
สตรีมจะทำหน้าที่เป็นไปป์ไลน์แบบขนานซึ่งประมวลผลเฟรมดิบ
ออกมาจากกล้องทีละเฟรม
![](https://developer.android.com/static/images/training/camera/camera2/capture-sessions-requests-1.png?authuser=5&hl=th)
การประมวลผลแบบขนานชี้ให้เห็นว่าอาจมีขีดจำกัดด้านประสิทธิภาพ ทั้งนี้ขึ้นอยู่กับ กำลังการประมวลผลที่พร้อมใช้งานจาก CPU, GPU หรือตัวประมวลผลอื่นๆ หากมี ไปป์ไลน์ตอบสนองต่อเฟรมที่เข้ามาใหม่ไม่ได้ และจะเริ่มวางเฟรมลง
ไปป์ไลน์แต่ละรายการมีรูปแบบเอาต์พุตของตัวเอง ข้อมูลดิบที่ส่งมาคือ
โดยอัตโนมัติเป็น
รูปแบบเอาต์พุตตามตรรกะโดยนัย
ที่เกี่ยวข้องกับแต่ละไปป์ไลน์ CameraDevice
ที่ใช้ทั่วทั้งหน้านี้
ตัวอย่างโค้ดไม่เจาะจง คุณจึงต้องแจกแจงก่อน
กล้องทั้งหมดที่พร้อมใช้งานก่อนดำเนินการต่อ
คุณสามารถใช้ CameraDevice
เพื่อสร้าง
CameraCaptureSession
,
โดยเฉพาะสำหรับ CameraDevice
ดังกล่าว CameraDevice
ต้องได้รับแอตทริบิวต์
การกำหนดค่าเฟรมสำหรับเฟรมดิบแต่ละเฟรมโดยใช้ CameraCaptureSession
การกำหนดค่า จะระบุคุณลักษณะของกล้อง เช่น โฟกัสอัตโนมัติ รูรับแสง เอฟเฟกต์
และจำนวนผู้ที่เห็น เนื่องจากข้อจำกัดด้านฮาร์ดแวร์ การกำหนดค่าแบบใดแบบหนึ่งเท่านั้น
อยู่ในเซ็นเซอร์กล้องในช่วงเวลาใดเวลาหนึ่ง ซึ่งเรียกว่า
active
อย่างไรก็ตาม กรณีการใช้งานของสตรีมจะเพิ่มประสิทธิภาพและขยายขอบเขตของการใช้ CameraDevice
ก่อนหน้านี้
เพื่อสตรีมเซสชันการจับภาพ ซึ่งจะช่วยให้คุณเพิ่มประสิทธิภาพสตรีมของกล้องสำหรับ
Use Case เฉพาะ เช่น ปรับปรุงอายุการใช้งานแบตเตอรี่เมื่อเพิ่มประสิทธิภาพ
วิดีโอคอล
CameraCaptureSession
จะอธิบายไปป์ไลน์ทั้งหมดที่เป็นไปได้ซึ่งผูกกับ
CameraDevice
เมื่อสร้างเซสชันแล้ว คุณจะเพิ่มหรือนำไปป์ไลน์ออกไม่ได้
CameraCaptureSession
รักษาคิวของ
CaptureRequest
วินาที
ซึ่งจะกลายเป็นการกำหนดค่าที่ใช้งานอยู่
CaptureRequest
จะเพิ่มการกำหนดค่าลงในคิวและเลือก 1 รายการ เช่น
ไปป์ไลน์หนึ่งรายการหรือทั้งหมดที่มีอยู่เพื่อรับเฟรมจาก
CameraDevice
คุณส่งคำขอจับภาพได้หลายรายการตลอดอายุการจับภาพ
เซสชัน แต่ละคำขอจะเปลี่ยนการกำหนดค่าและชุดเอาต์พุตที่ใช้งานอยู่ได้
ไปป์ไลน์ที่ได้รับรูปภาพดิบ
ใช้กรณีการใช้งานของสตรีมเพื่อประสิทธิภาพที่ดีขึ้น
กรณีการใช้งานของสตรีมเป็นวิธีปรับปรุงประสิทธิภาพการจับภาพของ Camera2 เซสชัน โดยให้ข้อมูลเพิ่มเติมแก่อุปกรณ์ฮาร์ดแวร์ในการปรับแต่งพารามิเตอร์ ซึ่งมอบประสบการณ์การใช้งานกล้องที่ดียิ่งขึ้นสำหรับงานที่เฉพาะเจาะจงของคุณ
ช่วงเวลานี้
ช่วยให้อุปกรณ์กล้องเพิ่มประสิทธิภาพฮาร์ดแวร์กล้องและไปป์ไลน์ซอฟต์แวร์
ตามสถานการณ์ของผู้ใช้สำหรับแต่ละสตรีม ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้สตรีม
กรณีต่างๆ โปรดดู setStreamUseCase
กรณีการใช้งานของสตรีมช่วยให้คุณระบุวิธีใช้สตรีมจากกล้องหนึ่งๆ ได้ใน
รายละเอียดมากขึ้น นอกเหนือจากการตั้งค่าเทมเพลตใน
CameraDevice.createCaptureRequest()
วิธีนี้จะช่วยให้ฮาร์ดแวร์กล้องเพิ่มประสิทธิภาพได้
เช่น การปรับแต่ง โหมดเซ็นเซอร์ หรือการตั้งค่าเซ็นเซอร์ของกล้องตาม
จะเกี่ยวข้องกับคุณภาพหรือเวลาในการตอบสนองที่เหมาะกับ Use Case ที่เฉพาะเจาะจง
กรณีการใช้งานของสตรีมมีดังนี้
DEFAULT
: ครอบคลุมการทำงานของแอปพลิเคชันที่มีอยู่ทั้งหมด เทียบเท่ากับการไม่ ตั้งค่า Use Case ของสตรีมPREVIEW
: แนะนำสำหรับการวิเคราะห์ช่องมองภาพหรือรูปภาพในแอปSTILL_CAPTURE
: เพิ่มประสิทธิภาพเพื่อการถ่ายภาพความละเอียดสูง ไม่ใช่ จะยังคงรักษาอัตราเฟรมเหมือนตัวอย่างได้VIDEO_RECORD
: เพิ่มประสิทธิภาพเพื่อการบันทึกวิดีโอคุณภาพสูง รวมถึงคุณภาพสูง การป้องกันภาพสั่นไหว หากอุปกรณ์และมีการเปิดใช้งานโดยแอปพลิเคชัน ตัวเลือกนี้อาจสร้างเฟรมเอาต์พุตที่มีเวลาหน่วงอย่างมากจากแบบเรียลไทม์ เพื่อการป้องกันภาพสั่นไหวที่มีคุณภาพสูงสุดหรือเพื่อการประมวลผลอื่นๆVIDEO_CALL
: แนะนำสำหรับกล้องที่ใช้งานเป็นเวลานานเมื่อการระบายพลังงาน ข้อกังวลPREVIEW_VIDEO_STILL
: แนะนำสำหรับแอปโซเชียลมีเดียหรือการใช้สตรีมเดียว กรณี เป็นสตรีมอเนกประสงค์VENDOR_START
: ใช้สำหรับ Use Case ที่ OEM กำหนด
สร้าง CameraCaptureSession
หากต้องการสร้างเซสชันของกล้อง ให้ใส่บัฟเฟอร์เอาต์พุตอย่างน้อย 1 รายการ ที่แอปของคุณสามารถเขียนเฟรมเอาต์พุตได้ บัฟเฟอร์แต่ละรายการแสดงถึงไปป์ไลน์ คุณต้อง ทำแบบนี้ก่อนเริ่มใช้กล้องเพื่อให้เฟรมเวิร์กสามารถกำหนดค่า ไปป์ไลน์ภายในของอุปกรณ์และจัดสรรบัฟเฟอร์หน่วยความจำสำหรับการส่งเฟรม ไปยังเป้าหมายเอาต์พุตที่ต้องการ
ข้อมูลโค้ดต่อไปนี้จะแสดงวิธีเตรียมเซสชันของกล้อง
เอาต์พุตบัฟเฟอร์ซึ่งเป็นของ
SurfaceView
และอีกโดเมนไปยัง
ImageReader
การเพิ่มกรณีการใช้งานสตรีม PREVIEW
ไปยัง previewSurface
และ
การใช้สตรีม STILL_CAPTURE
เคสที่จะimReaderSurface
ช่วยให้ฮาร์ดแวร์ของอุปกรณ์เพิ่มประสิทธิภาพสตรีมเหล่านี้ได้แม้
ต่อไป
Kotlin
// Retrieve the target surfaces, which might be coming from a number of places: // 1. SurfaceView, if you want to display the image directly to the user // 2. ImageReader, if you want to read each frame or perform frame-by-frame // analysis // 3. OpenGL Texture or TextureView, although discouraged for maintainability reasons // 4. RenderScript.Allocation, if you want to do parallel processing val surfaceView = findViewByIdS<urfaceView(>...) val imageReader = ImageReader.newInstance(...) // Remember to call this only *after* SurfaceHolder.Callback.surfaceCreated() val previewSurface = surfaceView.holder.surface val imReaderSurface = imageReader.surface val targets = listOf(previewSurface, imReaderSurface) // Create a capture session using the predefined targets; this also involves // defining the session state callback to be notified of when the session is // ready // Setup Stream Use Case while setting up your Output Configuration. @RequiresApi(Build.VERSION_CODES.TIRAMISU) fun configureSession(device: CameraDevice, targets: ListS<urface)>{ val configs = mutableListOfO<utputConfiguration(>) val streamUseCase = CameraMetadata .SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL targets.forEach { val config = OutputConfiguration(it) config.streamUseCase = streamUseCase.toLong() configs.add(config) } ... device.createCaptureSession(session) }
Java
// Retrieve the target surfaces, which might be coming from a number of places: // 1. SurfaceView, if you want to display the image directly to the user // 2. ImageReader, if you want to read each frame or perform frame-by-frame analysis // 3. RenderScript.Allocation, if you want to do parallel processing // 4. OpenGL Texture or TextureView, although discouraged for maintainability reasons Surface surfaceView = findViewByIdS<urfaceView(>...); ImageReader imageReader = ImageReader.newInstance(...); // Remember to call this only *after* SurfaceHolder.Callback.surfaceCreated() Surface previewSurface = surfaceView.getHolder().getSurface(); Surface imageSurface = imageReader.getSurface(); ListS<urface >targets = Arrays.asList(previewSurface, imageSurface); // Create a capture session using the predefined targets; this also involves defining the // session state callback to be notified of when the session is ready private void configureSession(CameraDevice device, ListS<urface >targets){ ArrayListO<utputConfiguration >configs= new ArrayList() String streamUseCase= CameraMetadata .SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL for(Surface s : targets){ OutputConfiguration config = new OutputConfiguration(s) config.setStreamUseCase(String.toLong(streamUseCase)) configs.add(config) } device.createCaptureSession(session) }
ณ จุดนี้ คุณยังไม่ได้กำหนดการกำหนดค่าที่ใช้งานอยู่ของกล้อง เมื่อกำหนดค่าเซสชันแล้ว คุณจะสร้างและส่งการจับภาพได้ คำขอให้ดำเนินการดังกล่าว
การเปลี่ยนรูปแบบที่ใช้กับอินพุตขณะเขียนลงในบัฟเฟอร์คือ
ตามประเภทของแต่ละเป้าหมาย ซึ่งต้องเป็น
Surface
เฟรมเวิร์ก Android รู้วิธี
แปลงรูปภาพดิบในการกำหนดค่าที่ใช้งานอยู่เป็นรูปแบบที่เหมาะสมสำหรับ
แต่ละเป้าหมาย Conversion ถูกควบคุมโดยรูปแบบพิกเซลและขนาดของฟิลด์
Surface
โดยเฉพาะ
เฟรมเวิร์กนี้จะพยายามทำให้ดีที่สุด แต่บางSurface
ชุดค่าผสมการกำหนดค่าอาจไม่ทำงาน ซึ่งจะทำให้เกิดปัญหาอย่างเช่น เซสชัน
ไม่มีการสร้าง แสดงข้อผิดพลาดรันไทม์เมื่อคุณส่งคำขอ หรือ
ประสิทธิภาพการทำงานที่ลดลง เฟรมเวิร์กนี้มีการรับประกันสำหรับ
ชุดค่าผสมของพารามิเตอร์อุปกรณ์ พื้นผิว และคำขอ เอกสารสำหรับ
createCaptureSession()
ให้ข้อมูลเพิ่มเติม
CaptureRequests เดี่ยว
การกำหนดค่าที่ใช้สำหรับแต่ละเฟรมจะเข้ารหัสเป็น CaptureRequest
ซึ่งเป็น
ที่ส่งไปยังกล้อง หากต้องการสร้างคำขอบันทึก คุณสามารถใช้
กำหนดไว้ล่วงหน้า
เทมเพลต
หรือใช้ TEMPLATE_MANUAL
เพื่อควบคุมได้อย่างสมบูรณ์ เมื่อคุณเลือก
เทมเพลต คุณต้องใส่บัฟเฟอร์เอาต์พุตอย่างน้อย 1 รายการเพื่อใช้กับ
คำขอ คุณสามารถใช้เฉพาะบัฟเฟอร์ที่กำหนดไว้แล้วในการบันทึก
เซสชันที่คุณต้องการใช้
คำขอบันทึกใช้
รูปแบบของเครื่องมือสร้าง
และให้โอกาสนักพัฒนาซอฟต์แวร์ในการตั้งค่า
ตัวเลือกอื่น ได้แก่
การรับแสงอัตโนมัติ
โฟกัสอัตโนมัติ
และ
รูรับแสงของเลนส์
ก่อนตั้งค่าช่อง โปรดตรวจสอบว่าตัวเลือกที่เจาะจงใช้ได้กับ
อุปกรณ์ด้วยการโทร
CameraCharacteristics.getAvailableCaptureRequestKeys()
และตรวจสอบว่าได้ค่าที่ต้องการด้วยการตรวจสอบกล้องที่เหมาะสม
ลักษณะเฉพาะ เช่น การรับแสงอัตโนมัติที่ใช้ได้
โหมดต่างๆ
วิธีสร้างคำขอบันทึกสำหรับ SurfaceView
โดยใช้เทมเพลต
ออกแบบมาเพื่อการแสดงตัวอย่างโดยไม่ต้องแก้ไขอะไรเลย ใช้
CameraDevice.TEMPLATE_PREVIEW
:
Kotlin
val session: CameraCaptureSession = ... // from CameraCaptureSession.StateCallback val captureRequest = session.device.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) captureRequest.addTarget(previewSurface)
Java
CameraCaptureSession session = ...; // from CameraCaptureSession.StateCallback CaptureRequest.Builder captureRequest = session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); captureRequest.addTarget(previewSurface);
เมื่อกำหนดคำขอบันทึกแล้ว ตอนนี้คุณจะมอบหมายได้ ไปยังเซสชันของกล้อง
Kotlin
val session: CameraCaptureSession = ... // from CameraCaptureSession.StateCallback val captureRequest: CaptureRequest = ... // from CameraDevice.createCaptureRequest() // The first null argument corresponds to the capture callback, which you // provide if you want to retrieve frame metadata or keep track of failed capture // requests that can indicate dropped frames; the second null argument // corresponds to the Handler used by the asynchronous callback, which falls // back to the current thread's looper if null session.capture(captureRequest.build(), null, null)
Java
CameraCaptureSession session = ...; // from CameraCaptureSession.StateCallback CaptureRequest captureRequest = ...; // from CameraDevice.createCaptureRequest() // The first null argument corresponds to the capture callback, which you // provide if you want to retrieve frame metadata or keep track of failed // capture // requests that can indicate dropped frames; the second null argument // corresponds to the Handler used by the asynchronous callback, which falls // back to the current thread's looper if null session.capture(captureRequest.build(), null, null);
เมื่อมีการใส่เฟรมเอาต์พุตในบัฟเฟอร์ที่เฉพาะเจาะจง จับภาพ
Callback
มีการทริกเกอร์ ในหลายกรณีของ Callback เพิ่มเติม เช่น
ImageReader.OnImageAvailableListener
ถูกเรียกใช้เมื่อเฟรมที่อยู่ในเฟรมได้รับการประมวลผล จัดขึ้นในเวลา
คุณจึงสามารถเรียกดูข้อมูลภาพจากบัฟเฟอร์ที่ระบุได้
CaptureRequests ซ้ำ
คำขอกล้องตัวเดียวนั้นทำได้ง่าย แต่สำหรับการแสดงการถ่ายทอดสด หรือวิดีโอ ไม่ค่อยเป็นประโยชน์ ในกรณีนี้ คุณจะต้องได้รับ สตรีมเฟรมอย่างต่อเนื่อง ไม่ใช่แค่เฟรมเดียว ข้อมูลโค้ดต่อไปนี้ แสดงวิธีการเพิ่ม คำขอซ้ำๆ กับเซสชัน:
Kotlin
val session: CameraCaptureSession = ... // from CameraCaptureSession.StateCallback val captureRequest: CaptureRequest = ... // from CameraDevice.createCaptureRequest() // This keeps sending the capture request as frequently as possible until // the // session is torn down or session.stopRepeating() is called // session.setRepeatingRequest(captureRequest.build(), null, null)
Java
CameraCaptureSession session = ...; // from CameraCaptureSession.StateCallback CaptureRequest captureRequest = ...; // from CameraDevice.createCaptureRequest() // This keeps sending the capture request as frequently as possible until the // session is torn down or session.stopRepeating() is called // session.setRepeatingRequest(captureRequest.build(), null, null);
คำขอจับภาพซ้ำทำให้อุปกรณ์กล้องจับภาพได้อย่างต่อเนื่อง
โดยใช้การตั้งค่าใน CaptureRequest
ที่ให้ไว้ Camera2 API
ยังช่วยให้ผู้ใช้จับภาพวิดีโอจากกล้องได้โดยการส่ง
ทำซ้ำ CaptureRequests
ตามที่เห็นใน
ตัวอย่าง Camera2
ใน GitHub และยังสามารถแสดงผลวิดีโอสโลว์โมชันด้วยการจับภาพ
วิดีโอความเร็วสูง (สโลว์โมชัน) ที่ใช้การถ่ายภาพอัจฉริยะซ้ำ CaptureRequests
ตามที่แสดงในแอปตัวอย่างวิดีโอสโลว์โมชัน Camera2
ใน GitHub
การจับภาพคำขอแบบแทรกสลับ
หากต้องการส่งคำขอจับภาพที่ 2 ขณะที่คำขอบันทึกซ้ำทำงานอยู่ เช่น เพื่อแสดงช่องมองภาพ และให้ผู้ใช้ถ่ายภาพ คุณไม่จำเป็นต้อง หยุดคำขอซ้ำที่ดำเนินอยู่ แต่คุณจะออกบันทึกที่ไม่ซ้ำกันแทน ขณะที่คำขอซ้ำยังทำงานต่อไป
ต้องกำหนดค่าบัฟเฟอร์เอาต์พุตที่ใช้ให้เป็นส่วนหนึ่งของเซสชันกล้อง เมื่อสร้างเซสชันเป็นครั้งแรก คำขอซ้ำมีลำดับความสำคัญต่ำกว่า คำขอแบบเฟรมเดียวหรือแบบต่อเนื่อง ซึ่งช่วยให้ตัวอย่างต่อไปนี้ทำงานได้:
Kotlin
val session: CameraCaptureSession = ... // from CameraCaptureSession.StateCallback // Create the repeating request and dispatch it val repeatingRequest = session.device.createCaptureRequest( CameraDevice.TEMPLATE_PREVIEW) repeatingRequest.addTarget(previewSurface) session.setRepeatingRequest(repeatingRequest.build(), null, null) // Some time later... // Create the single request and dispatch it // NOTE: This can disrupt the ongoing repeating request momentarily val singleRequest = session.device.createCaptureRequest( CameraDevice.TEMPLATE_STILL_CAPTURE) singleRequest.addTarget(imReaderSurface) session.capture(singleRequest.build(), null, null)
Java
CameraCaptureSession session = ...; // from CameraCaptureSession.StateCallback // Create the repeating request and dispatch it CaptureRequest.Builder repeatingRequest = session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); repeatingRequest.addTarget(previewSurface); session.setRepeatingRequest(repeatingRequest.build(), null, null); // Some time later... // Create the single request and dispatch it // NOTE: This can disrupt the ongoing repeating request momentarily CaptureRequest.Builder singleRequest = session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); singleRequest.addTarget(imReaderSurface); session.capture(singleRequest.build(), null, null);
วิธีนี้มีข้อเสียคือ คุณจะไม่ทราบแน่ชัดว่าเมื่อใด คำขอเดียวจะเกิดขึ้น ในรูปต่อไปนี้ หาก A คือการทำซ้ำ และ B เป็นคำขอจับภาพแบบเฟรมเดียว ซึ่งเป็นวิธีที่ เซสชันจะประมวลผลคิวคำขอ
![](https://developer.android.com/static/images/training/camera/camera2/capture-sessions-requests-2.png?authuser=5&hl=th)
ไม่มีการรับประกันเวลาในการตอบสนองระหว่างคำขอที่เกิดซ้ำล่าสุดจาก A ก่อนคำขอ B จะทำงานและครั้งถัดไปที่มีการใช้ A คุณจึงอาจเห็นว่าเฟรมบางเฟรมถูกข้าม มีบางสิ่งที่คุณ เพื่อลดปัญหานี้ได้
เพิ่มเป้าหมายเอาต์พุตจากคำขอ A เพื่อขอ B วิธีนี้จะทำให้ เฟรมของ B พร้อมใช้งานแล้ว ระบบจะคัดลอกไปยังเป้าหมายเอาต์พุตของ A ตัวอย่างเช่น สิ่งนี้เป็นสิ่งจำเป็นในการสร้างสแนปชอตวิดีโอเพื่อคงรักษา อัตราเฟรมคงที่ ในโค้ดก่อนหน้านี้ คุณเพิ่ม
singleRequest.addTarget(previewSurface)
ก่อนสร้างคำขอใช้เทมเพลตต่างๆ ร่วมกันซึ่งออกแบบมาเพื่อสถานการณ์นี้โดยเฉพาะ เช่น Zero-shutter-lag