ใช้สตรีมจากกล้องหลายตัวพร้อมกัน

หมายเหตุ: หน้านี้เกี่ยวข้องกับแพ็กเกจ camera2 เราขอแนะนำให้ใช้ cameraX เว้นแต่ว่าแอปของคุณต้องใช้ฟีเจอร์ระดับต่ำที่เฉพาะเจาะจงจาก Camera2 ทั้ง CameraX และ Camera2 รองรับ Android 5.0 (API ระดับ 21) ขึ้นไป

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

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

ต้นทุนด้านประสิทธิภาพที่ไม่สำคัญเมื่อประมวลผลเฟรม และค่าใช้จ่าย คูณเมื่อประมวลผลสตรีมคู่ขนานหรือไปป์ไลน์

ทรัพยากร เช่น CPU, GPU และ DSP อาจใช้ประโยชน์จาก การประมวลผลใหม่ของเฟรมเวิร์ก แต่ทรัพยากรอย่างหน่วยความจำ จะเติบโตเป็นเส้นตรง

เป้าหมายหลายรายการต่อคำขอ

สตรีมจากกล้องหลายรายการสามารถรวมเป็นสตรีมเดียว CameraCaptureRequest ข้อมูลโค้ดต่อไปนี้จะแสดงวิธีตั้งค่าเซสชันของกล้องด้วย สตรีมเพื่อดูตัวอย่างจากกล้องและสตรีมอื่นสำหรับการประมวลผลรูปภาพ

Kotlin

val session: CameraCaptureSession = ...  // from CameraCaptureSession.StateCallback

// You will use the preview capture template for the combined streams
// because it is optimized for low latency; for high-quality images, use
// TEMPLATE_STILL_CAPTURE, and for a steady frame rate use TEMPLATE_RECORD
val requestTemplate = CameraDevice.TEMPLATE_PREVIEW
val combinedRequest = session.device.createCaptureRequest(requestTemplate)

// Link the Surface targets with the combined request
combinedRequest.addTarget(previewSurface)
combinedRequest.addTarget(imReaderSurface)

// In this simple case, the SurfaceView gets updated automatically. ImageReader
// has its own callback that you have to listen to in order to retrieve the
// frames so there is no need to set up a callback for the capture request
session.setRepeatingRequest(combinedRequest.build(), null, null)

Java

CameraCaptureSession session = …;  // from CameraCaptureSession.StateCallback

// You will use the preview capture template for the combined streams
// because it is optimized for low latency; for high-quality images, use
// TEMPLATE_STILL_CAPTURE, and for a steady frame rate use TEMPLATE_RECORD
        CaptureRequest.Builder combinedRequest = session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);

// Link the Surface targets with the combined request
        combinedRequest.addTarget(previewSurface);
        combinedRequest.addTarget(imReaderSurface);

// In this simple case, the SurfaceView gets updated automatically. ImageReader
// has its own callback that you have to listen to in order to retrieve the
// frames so there is no need to set up a callback for the capture request
        session.setRepeatingRequest(combinedRequest.build(), null, null);

หากคุณกำหนดค่าแพลตฟอร์มเป้าหมายอย่างถูกต้อง โค้ดนี้จะสร้างเฉพาะ สตรีมที่มี FPS ขั้นต่ำซึ่งกำหนดโดย StreamComfigurationMap.GetOutputMinFrameDuration(int, Size) และ StreamComfigurationMap.GetOutputStallDuration(int, Size) ประสิทธิภาพจริงจะแตกต่างกันไปตามแต่ละอุปกรณ์ แม้ว่า Android จะมี รับประกันการรองรับชุดค่าผสมที่เฉพาะเจาะจงโดยขึ้นอยู่กับตัวแปร 3 ตัว ดังนี้ ประเภทเอาต์พุต ขนาดเอาต์พุต และระดับฮาร์ดแวร์

การใช้ตัวแปรที่ใช้ร่วมกันที่ไม่รองรับอาจใช้งานกับอัตราเฟรมต่ำได้ ถ้า ไม่ จะทริกเกอร์การเรียกกลับที่ล้มเหลวรายการใดรายการหนึ่ง เอกสารสำหรับ createCaptureSession อธิบายถึงสิ่งที่รับประกันว่าได้ผล

ประเภทเอาต์พุต

ประเภทเอาต์พุตหมายถึงรูปแบบการเข้ารหัสเฟรม ค่าที่เป็นไปได้คือ PRIV, YUV, JPEG และ RAW เอกสารสำหรับ createCaptureSession อธิบายถึงพวกเขา

เมื่อเลือกประเภทเอาต์พุตของแอปพลิเคชัน หากเป้าหมายคือการเพิ่ม ความเข้ากันได้แล้วใช้ ImageFormat.YUV_420_888 เพื่อวิเคราะห์เฟรมและ ImageFormat.JPEG สำหรับภาพนิ่ง รูปภาพ สำหรับสถานการณ์ตัวอย่างและการบันทึก คุณมีแนวโน้มที่จะใช้ SurfaceView TextureView MediaRecorder MediaCodec หรือ RenderScript.Allocation ใน ในกรณีเช่นนี้ อย่าระบุรูปแบบภาพ สำหรับความเข้ากันได้ ระบบจะนับเป็น ImageFormat.PRIVATE โดยไม่คำนึงถึงรูปแบบจริงที่ใช้เป็นการภายใน เพื่อค้นหารูปแบบที่รองรับ ตามอุปกรณ์ CameraCharacteristics ใช้รหัสต่อไปนี้

Kotlin

val characteristics: CameraCharacteristics = ...
val supportedFormats = characteristics.get(
    CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).outputFormats

Java

CameraCharacteristics characteristics = …;
        int[] supportedFormats = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputFormats();

ขนาดเอาต์พุต

ขนาดเอาต์พุตทั้งหมดที่มีจะแสดงตาม StreamConfigurationMap.getOutputSizes() แต่มีแค่ 2 รายการที่เกี่ยวข้องกับความเข้ากันได้ นั่นคือ PREVIEW และ MAXIMUM ขนาด ทำหน้าที่เป็นขอบเขตบน หากขนาด PREVIEW ใช้งานได้ ผลิตภัณฑ์ใดก็ตามที่มี ขนาดที่เล็กกว่า PREVIEW ก็จะใช้ได้เช่นกัน เช่นเดียวกันกับ MAXIMUM เอกสารประกอบสำหรับ CameraDevice อธิบายถึงขนาดเหล่านี้

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

Kotlin

val characteristics: CameraCharacteristics = ...
val outputFormat: Int = ...  // such as ImageFormat.JPEG
val sizes = characteristics.get(
    CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
    .getOutputSizes(outputFormat)

Java

CameraCharacteristics characteristics = …;
        int outputFormat = …;  // such as ImageFormat.JPEG
Size[] sizes = characteristics.get(
                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
                .getOutputSizes(outputFormat);

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

Kotlin

val characteristics: CameraCharacteristics = ...
val targetClass: Class <T> = ...  // such as SurfaceView::class.java
val sizes = characteristics.get(
    CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
    .getOutputSizes(targetClass)

Java

CameraCharacteristics characteristics = …;
   int outputFormat = …;  // such as ImageFormat.JPEG
   Size[] sizes = characteristics.get(
                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
                .getOutputSizes(outputFormat);

หากต้องการดูขนาด MAXIMUM ให้จัดเรียงขนาดเอาต์พุตตามพื้นที่และแสดงขนาดที่ใหญ่ที่สุด หนึ่ง:

Kotlin

fun <T>getMaximumOutputSize(
    characteristics: CameraCharacteristics, targetClass: Class <T>, format: Int? = null):
    Size {
  val config = characteristics.get(
      CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)

  // If image format is provided, use it to determine supported sizes; or else use target class
  val allSizes = if (format == null)
    config.getOutputSizes(targetClass) else config.getOutputSizes(format)
  return allSizes.maxBy { it.height * it.width }
}

Java

 @RequiresApi(api = Build.VERSION_CODES.N)
    <T> Size getMaximumOutputSize(CameraCharacteristics characteristics,
                                            Class <T> targetClass,
                                            Integer format) {
        StreamConfigurationMap config = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);

        // If image format is provided, use it to determine supported sizes; else use target class
        Size[] allSizes;
        if (format == null) {
            allSizes = config.getOutputSizes(targetClass);
        } else {
            allSizes = config.getOutputSizes(format);
        }
        return Arrays.stream(allSizes).max(Comparator.comparing(s -> s.getHeight() * s.getWidth())).get();
    }

PREVIEW หมายถึงขนาดที่เหมาะกับความละเอียดหน้าจอของอุปกรณ์มากที่สุดหรือ 1080p (1920x1080) ขึ้นอยู่กับว่ากรณีใดเล็กกว่า สัดส่วนภาพอาจไม่ตรงกับ สัดส่วนการแสดงผลของหน้าจอพอดี คุณจึงอาจต้องใช้แถบดำด้านบน-ล่างของภาพ หรือ ครอบตัดไปยังสตรีมเพื่อแสดงในโหมดเต็มหน้าจอ รับสิทธิ์ เปรียบเทียบขนาดเอาต์พุตที่พร้อมใช้งานกับขนาดการแสดงผล โดยไม่คำนึงว่าจอแสดงผลอาจมีการหมุน

รหัสต่อไปนี้กำหนดคลาสตัวช่วยชื่อ SmartSize ซึ่งจะกำหนดขนาด เปรียบเทียบได้ง่ายขึ้น

Kotlin

/** Helper class used to pre-compute shortest and longest sides of a [Size] */
class SmartSize(width: Int, height: Int) {
    var size = Size(width, height)
    var long = max(size.width, size.height)
    var short = min(size.width, size.height)
    override fun toString() = "SmartSize(${long}x${short})"
}

/** Standard High Definition size for pictures and video */
val SIZE_1080P: SmartSize = SmartSize(1920, 1080)

/** Returns a [SmartSize] object for the given [Display] */
fun getDisplaySmartSize(display: Display): SmartSize {
    val outPoint = Point()
    display.getRealSize(outPoint)
    return SmartSize(outPoint.x, outPoint.y)
}

/**
 * Returns the largest available PREVIEW size. For more information, see:
 * https://d.android.com/reference/android/hardware/camera2/CameraDevice
 */
fun <T>getPreviewOutputSize(
        display: Display,
        characteristics: CameraCharacteristics,
        targetClass: Class <T>,
        format: Int? = null
): Size {

    // Find which is smaller: screen or 1080p
    val screenSize = getDisplaySmartSize(display)
    val hdScreen = screenSize.long >= SIZE_1080P.long || screenSize.short >= SIZE_1080P.short
    val maxSize = if (hdScreen) SIZE_1080P else screenSize

    // If image format is provided, use it to determine supported sizes; else use target class
    val config = characteristics.get(
            CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)!!
    if (format == null)
        assert(StreamConfigurationMap.isOutputSupportedFor(targetClass))
    else
        assert(config.isOutputSupportedFor(format))
    val allSizes = if (format == null)
        config.getOutputSizes(targetClass) else config.getOutputSizes(format)

    // Get available sizes and sort them by area from largest to smallest
    val validSizes = allSizes
            .sortedWith(compareBy { it.height * it.width })
            .map { SmartSize(it.width, it.height) }.reversed()

    // Then, get the largest output size that is smaller or equal than our max size
    return validSizes.first { it.long <= maxSize.long && it.short <= maxSize.short }.size
}

Java

/** Helper class used to pre-compute shortest and longest sides of a [Size] */
    class SmartSize {
        Size size;
        double longSize;
        double shortSize;

        public SmartSize(Integer width, Integer height) {
            size = new Size(width, height);
            longSize = max(size.getWidth(), size.getHeight());
            shortSize = min(size.getWidth(), size.getHeight());
        }

        @Override
        public String toString() {
            return String.format("SmartSize(%sx%s)", longSize, shortSize);
        }
    }

    /** Standard High Definition size for pictures and video */
    SmartSize SIZE_1080P = new SmartSize(1920, 1080);

    /** Returns a [SmartSize] object for the given [Display] */
    SmartSize getDisplaySmartSize(Display display) {
        Point outPoint = new Point();
        display.getRealSize(outPoint);
        return new SmartSize(outPoint.x, outPoint.y);
    }

    /**
     * Returns the largest available PREVIEW size. For more information, see:
     * https://d.android.com/reference/android/hardware/camera2/CameraDevice
     */
    @RequiresApi(api = Build.VERSION_CODES.N)
    <T> Size getPreviewOutputSize(
            Display display,
            CameraCharacteristics characteristics,
            Class <T> targetClass,
            Integer format
    ){

        // Find which is smaller: screen or 1080p
        SmartSize screenSize = getDisplaySmartSize(display);
        boolean hdScreen = screenSize.longSize >= SIZE_1080P.longSize || screenSize.shortSize >= SIZE_1080P.shortSize;
        SmartSize maxSize;
        if (hdScreen) {
            maxSize = SIZE_1080P;
        } else {
            maxSize = screenSize;
        }

        // If image format is provided, use it to determine supported sizes; else use target class
        StreamConfigurationMap config = characteristics.get(
                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
        if (format == null)
            assert(StreamConfigurationMap.isOutputSupportedFor(targetClass));
        else
            assert(config.isOutputSupportedFor(format));
        Size[] allSizes;
        if (format == null) {
            allSizes = config.getOutputSizes(targetClass);
        } else {
            allSizes = config.getOutputSizes(format);
        }

        // Get available sizes and sort them by area from largest to smallest
        List <Size> sortedSizes = Arrays.asList(allSizes);
        List <SmartSize> validSizes =
                sortedSizes.stream()
                        .sorted(Comparator.comparing(s -> s.getHeight() * s.getWidth()))
                        .map(s -> new SmartSize(s.getWidth(), s.getHeight()))
                        .sorted(Collections.reverseOrder()).collect(Collectors.toList());

        // Then, get the largest output size that is smaller or equal than our max size
        return validSizes.stream()
                .filter(s -> s.longSize <= maxSize.longSize && s.shortSize <= maxSize.shortSize)
                .findFirst().get().size;
    }

ตรวจสอบระดับฮาร์ดแวร์ที่รองรับ

หากต้องการทราบความสามารถที่ใช้ได้ระหว่างรันไทม์ ให้ตรวจสอบฮาร์ดแวร์ที่รองรับ ระดับโดยใช้ CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL

พร้อม CameraCharacteristics คุณสามารถเรียกดูระดับฮาร์ดแวร์ด้วยคำสั่งเดียว:

Kotlin

val characteristics: CameraCharacteristics = ...

// Hardware level will be one of:
// - CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,
// - CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL,
// - CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED,
// - CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
// - CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3
val hardwareLevel = characteristics.get(
        CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL)

Java

CameraCharacteristics characteristics = ...;

// Hardware level will be one of:
// - CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,
// - CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL,
// - CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED,
// - CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
// - CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3
Integer hardwareLevel = characteristics.get(
                CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);

นำชิ้นส่วนทั้งหมดมารวมกัน

ด้วยประเภทเอาต์พุต ขนาดเอาต์พุต และระดับฮาร์ดแวร์ คุณสามารถกำหนดได้ว่า ชุดค่าผสมของสตรีมถูกต้อง แผนภูมิต่อไปนี้คือภาพรวมของ การกำหนดค่าที่รองรับโดย CameraDevice ที่มี LEGACY ระดับฮาร์ดแวร์

เป้าหมาย 1 เป้าหมาย 2 เป้าหมาย 3 ตัวอย่างกรณีการใช้งาน
ประเภท ขนาดสูงสุด ประเภท ขนาดสูงสุด ประเภท ขนาดสูงสุด
PRIV MAXIMUM การดูตัวอย่างอย่างง่าย การประมวลผลวิดีโอโดยใช้ GPU หรือการบันทึกวิดีโอแบบไม่มีตัวอย่าง
JPEG MAXIMUM การจับภาพนิ่งที่ไม่มีช่องมองภาพ
YUV MAXIMUM การประมวลผลวิดีโอ/รูปภาพในแอปพลิเคชัน
PRIV PREVIEW JPEG MAXIMUM ยังคงถ่ายภาพแบบมาตรฐานอยู่
YUV PREVIEW JPEG MAXIMUM การประมวลผลในแอปและยังคงจับภาพได้
PRIV PREVIEW PRIV PREVIEW การบันทึกมาตรฐาน
PRIV PREVIEW YUV PREVIEW แสดงตัวอย่างและการประมวลผลในแอป
PRIV PREVIEW YUV PREVIEW แสดงตัวอย่างและการประมวลผลในแอป
PRIV PREVIEW YUV PREVIEW JPEG MAXIMUM ยังคงจับภาพและประมวลผลในแอปอยู่

LEGACY คือระดับฮาร์ดแวร์ที่ต่ำที่สุดเท่าที่จะเป็นไปได้ ตารางนี้แสดงให้เห็นว่า อุปกรณ์ที่รองรับ Camera2 (API ระดับ 21 และสูงกว่า) สามารถให้เอาต์พุตสูงสุดสาม การสตรีมพร้อมกันโดยใช้การกำหนดค่าที่ถูกต้อง และหากปริมาณไม่มากเกินไป โอเวอร์เฮดที่จำกัดประสิทธิภาพ เช่น ข้อจำกัดด้านหน่วยความจำ, CPU หรือความร้อน

แอปของคุณต้องกําหนดค่าบัฟเฟอร์เอาต์พุตการกำหนดเป้าหมายด้วย ตัวอย่างเช่น หากต้องการ กำหนดเป้าหมายอุปกรณ์ที่มีระดับฮาร์ดแวร์ LEGACY คุณอาจตั้งค่าเอาต์พุตเป้าหมาย 2 รายการ แพลตฟอร์มหนึ่งใช้ ImageFormat.PRIVATE และอีกแพลตฟอร์มหนึ่งใช้ ImageFormat.YUV_420_888 ซึ่งเป็นชุดค่าผสมที่รองรับเมื่อใช้ PREVIEW ขนาด การใช้ฟังก์ชันที่กำหนดไว้ก่อนหน้าในหัวข้อนี้ การเรียกฟังก์ชัน ขนาดตัวอย่างที่จําเป็นสําหรับรหัสกล้องต้องใช้โค้ดต่อไปนี้

Kotlin

val characteristics: CameraCharacteristics = ...
val context = this as Context  // assuming you are inside of an activity

val surfaceViewSize = getPreviewOutputSize(
    context, characteristics, SurfaceView::class.java)
val imageReaderSize = getPreviewOutputSize(
    context, characteristics, ImageReader::class.java, format = ImageFormat.YUV_420_888)

Java

CameraCharacteristics characteristics = ...;
        Context context = this; // assuming you are inside of an activity

        Size surfaceViewSize = getPreviewOutputSize(
                context, characteristics, SurfaceView.class);
        Size imageReaderSize = getPreviewOutputSize(
                context, characteristics, ImageReader.class, format = ImageFormat.YUV_420_888);

ต้องรอจนกระทั่ง SurfaceView พร้อมใช้งานโดยใช้ Callback ที่ให้มา

Kotlin

val surfaceView = findViewById <SurfaceView>(...)
surfaceView.holder.addCallback(object : SurfaceHolder.Callback {
  override fun surfaceCreated(holder: SurfaceHolder) {
    // You do not need to specify image format, and it will be considered of type PRIV
    // Surface is now ready and you could use it as an output target for CameraSession
  }
  ...
})

Java

SurfaceView surfaceView = findViewById <SurfaceView>(...);

surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) {
                // You do not need to specify image format, and it will be considered of type PRIV
                // Surface is now ready and you could use it as an output target for CameraSession
            }
            ...
        });

คุณสามารถบังคับให้ SurfaceView ตรงกับขนาดเอาต์พุตของกล้องได้โดยการเรียกใช้ SurfaceHolder.setFixedSize() หรือใช้แนวทางที่คล้ายกับ AutoFitSurfaceView จากช่อง Common โมดูล ตัวอย่างจากกล้องใน GitHub ซึ่งจะตั้งค่าขนาดสัมบูรณ์ คำนึงถึงทั้งสัดส่วนและพื้นที่ว่าง โดยอัตโนมัติ ปรับเมื่อมีการทริกเกอร์การเปลี่ยนแปลงของกิจกรรม

การตั้งค่าแพลตฟอร์มอื่นจาก ImageReader ที่มีรูปแบบที่ต้องการคือ ง่ายขึ้นเนื่องจากไม่มีการเรียกกลับให้รอ

Kotlin

val frameBufferCount = 3  // just an example, depends on your usage of ImageReader
val imageReader = ImageReader.newInstance(
    imageReaderSize.width, imageReaderSize.height, ImageFormat.YUV_420_888,
    frameBufferCount)

Java

int frameBufferCount = 3;  // just an example, depends on your usage of ImageReader
ImageReader imageReader = ImageReader.newInstance(
                imageReaderSize.width, imageReaderSize.height, ImageFormat.YUV_420_888,
                frameBufferCount);

เมื่อใช้บัฟเฟอร์เป้าหมายการบล็อก เช่น ImageReader ให้ทิ้งเฟรมหลังจาก โดยใช้

Kotlin

imageReader.setOnImageAvailableListener({
  val frame =  it.acquireNextImage()
  // Do something with "frame" here
  it.close()
}, null)

Java

imageReader.setOnImageAvailableListener(listener -> {
            Image frame = listener.acquireNextImage();
            // Do something with "frame" here
            listener.close();
        }, null);

ระดับฮาร์ดแวร์ LEGACY กำหนดเป้าหมายไปยังอุปกรณ์ตัวส่วนร่วมที่ต่ำที่สุด คุณสามารถ เพิ่มการแยกแบบมีเงื่อนไขและใช้ขนาด RECORD สำหรับเป้าหมายเอาต์พุตรายการใดรายการหนึ่ง ในอุปกรณ์ที่มีระดับฮาร์ดแวร์ LIMITED หรือแม้แต่เพิ่มระดับเป็น ขนาด MAXIMUM สำหรับอุปกรณ์ที่มีระดับฮาร์ดแวร์ FULL