หมายเหตุ: หน้านี้เกี่ยวข้องกับแพ็กเกจ camera2 เราขอแนะนำให้ใช้ cameraX เว้นแต่ว่าแอปของคุณต้องใช้ฟีเจอร์ระดับต่ำที่เฉพาะเจาะจงจาก Camera2 ทั้ง CameraX และ Camera2 รองรับ Android 5.0 (API ระดับ 21) ขึ้นไป
แอปพลิเคชันกล้องใช้สตรีมเฟรมได้มากกว่า 1 สตรีมพร้อมกัน ใน ในบางกรณี สตรีมที่แตกต่างกัน จำเป็นต้องใช้ความละเอียดของเฟรมหรือพิกเซลที่แตกต่างกัน กรณีการใช้งานทั่วไปมีดังนี้
- การบันทึกวิดีโอ: สตรีมหนึ่งสำหรับดูตัวอย่างและอีกสตรีมหนึ่งมีการเข้ารหัสและบันทึกไว้ เป็นไฟล์
- การสแกนบาร์โค้ด: สตรีมหนึ่งเพื่อแสดงตัวอย่าง และอีกสตรีมสำหรับการตรวจหาบาร์โค้ด
- การถ่ายภาพระบบคอมพิวเตอร์: สตรีมหนึ่งสำหรับดูตัวอย่างและอีกสตรีมหนึ่งสำหรับใบหน้า/ฉาก การตรวจจับ
ต้นทุนด้านประสิทธิภาพที่ไม่สำคัญเมื่อประมวลผลเฟรม และค่าใช้จ่าย คูณเมื่อประมวลผลสตรีมคู่ขนานหรือไปป์ไลน์
ทรัพยากร เช่น CPU, GPU และ DSP อาจใช้ประโยชน์จาก การประมวลผลใหม่ของเฟรมเวิร์ก แต่ทรัพยากรอย่างหน่วยความจำ จะเติบโตเป็นเส้นตรง
เป้าหมายหลายรายการต่อคำขอ
สตรีมจากกล้องหลายรายการสามารถรวมเป็นสตรีมเดียว
CameraCaptureRequest
ข้อมูลโค้ดต่อไปนี้จะแสดงวิธีตั้งค่าเซสชันของกล้องด้วย
สตรีมเพื่อดูตัวอย่างจากกล้องและสตรีมอื่นสำหรับการประมวลผลรูปภาพ
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)
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
ใช้รหัสต่อไปนี้
val characteristics: CameraCharacteristics = ...
val supportedFormats = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).outputFormats
CameraCharacteristics characteristics = …;
int[] supportedFormats = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputFormats();
ขนาดเอาต์พุต
ขนาดเอาต์พุตทั้งหมดที่มีจะแสดงตาม
StreamConfigurationMap.getOutputSizes()
แต่มีแค่ 2 รายการที่เกี่ยวข้องกับความเข้ากันได้ นั่นคือ PREVIEW
และ MAXIMUM
ขนาด
ทำหน้าที่เป็นขอบเขตบน หากขนาด PREVIEW
ใช้งานได้ ผลิตภัณฑ์ใดก็ตามที่มี
ขนาดที่เล็กกว่า PREVIEW
ก็จะใช้ได้เช่นกัน เช่นเดียวกันกับ MAXIMUM
เอกสารประกอบสำหรับ
CameraDevice
อธิบายถึงขนาดเหล่านี้
ขนาดเอาต์พุตที่ใช้ได้จะขึ้นอยู่กับรูปแบบที่เลือก เนื่องจาก
CameraCharacteristics
ที่มีรูปแบบ คุณสามารถค้นหาขนาดเอาต์พุตที่ใช้ได้ ดังนี้
val characteristics: CameraCharacteristics = ...
val outputFormat: Int = ... // such as ImageFormat.JPEG
val sizes = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
.getOutputSizes(outputFormat)
CameraCharacteristics characteristics = …;
int outputFormat = …; // such as ImageFormat.JPEG
Size[] sizes = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
.getOutputSizes(outputFormat);
ในการแสดงตัวอย่างจากกล้องและกรณีการใช้งานการบันทึก ให้ใช้คลาสเป้าหมายเพื่อระบุ ขนาดที่รองรับ เฟรมเวิร์กกล้องจะจัดการรูปแบบเอง ดังนี้
val characteristics: CameraCharacteristics = ...
val targetClass: Class <T> = ... // such as SurfaceView::class.java
val sizes = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
.getOutputSizes(targetClass)
CameraCharacteristics characteristics = …;
int outputFormat = …; // such as ImageFormat.JPEG
Size[] sizes = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
.getOutputSizes(outputFormat);
หากต้องการดูขนาด MAXIMUM
ให้จัดเรียงขนาดเอาต์พุตตามพื้นที่และแสดงขนาดที่ใหญ่ที่สุด
หนึ่ง:
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 }
}
@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
ซึ่งจะกำหนดขนาด
เปรียบเทียบได้ง่ายขึ้น
/** 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
}
/** 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
คุณสามารถเรียกดูระดับฮาร์ดแวร์ด้วยคำสั่งเดียว:
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)
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
ขนาด การใช้ฟังก์ชันที่กำหนดไว้ก่อนหน้าในหัวข้อนี้ การเรียกฟังก์ชัน
ขนาดตัวอย่างที่จําเป็นสําหรับรหัสกล้องต้องใช้โค้ดต่อไปนี้
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)
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 ที่ให้มา
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
}
...
})
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
ที่มีรูปแบบที่ต้องการคือ
ง่ายขึ้นเนื่องจากไม่มีการเรียกกลับให้รอ
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)
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
ให้ทิ้งเฟรมหลังจาก
โดยใช้
imageReader.setOnImageAvailableListener({
val frame = it.acquireNextImage()
// Do something with "frame" here
it.close()
}, null)
imageReader.setOnImageAvailableListener(listener -> {
Image frame = listener.acquireNextImage();
// Do something with "frame" here
listener.close();
}, null);
ระดับฮาร์ดแวร์ LEGACY
กำหนดเป้าหมายไปยังอุปกรณ์ตัวส่วนร่วมที่ต่ำที่สุด คุณสามารถ
เพิ่มการแยกแบบมีเงื่อนไขและใช้ขนาด RECORD
สำหรับเป้าหมายเอาต์พุตรายการใดรายการหนึ่ง
ในอุปกรณ์ที่มีระดับฮาร์ดแวร์ LIMITED
หรือแม้แต่เพิ่มระดับเป็น
ขนาด MAXIMUM
สำหรับอุปกรณ์ที่มีระดับฮาร์ดแวร์ FULL