หมายเหตุ: หน้านี้อ้างอิงถึงแพ็กเกจ Camera2 เราขอแนะนำให้ใช้ CameraX เว้นแต่ว่าแอปของคุณต้องใช้ฟีเจอร์ระดับต่ำที่เฉพาะเจาะจงจาก Camera2 ทั้ง CameraX และ Camera2 รองรับ Android 5.0 (API ระดับ 21) ขึ้นไป
แอปพลิเคชันกล้องสามารถใช้เฟรมมากกว่า 1 สตรีมพร้อมกันได้ ในบางกรณี สตรีมที่ต่างกันอาจต้องใช้ความละเอียดเฟรมหรือรูปแบบพิกเซลที่ต่างกันด้วย กรณีการใช้งานทั่วไปมีดังนี้
- การบันทึกวิดีโอ: สตรีมหนึ่งสำหรับการแสดงตัวอย่าง และอีกสตรีมหนึ่งจะได้รับการเข้ารหัสและบันทึกลงในไฟล์
- การสแกนบาร์โค้ด: สตรีมหนึ่งสำหรับการแสดงตัวอย่าง และอีกสตรีมหนึ่งสำหรับการตรวจจับบาร์โค้ด
- การถ่ายภาพแบบดิจิทัล: สตรีมหนึ่งสำหรับแสดงตัวอย่าง และอีกสตรีมหนึ่งสำหรับการตรวจจับใบหน้าหรือฉาก
การประมวลผลเฟรมมีต้นทุนด้านประสิทธิภาพที่สำคัญ และต้นทุนจะเพิ่มขึ้นเมื่อประมวลผลสตรีมหรือไปป์ไลน์แบบขนาน
ทรัพยากรต่างๆ เช่น CPU, GPU และ DSP อาจใช้ประโยชน์จากความสามารถในการประมวลผลซ้ำของเฟรมเวิร์กได้ แต่ทรัพยากรอย่างหน่วยความจำจะเพิ่มขึ้นแบบเชิงเส้น
เป้าหมายหลายรายการต่อคำขอ
คุณสามารถรวมสตรีมจากกล้องหลายรายการไว้ใน CameraCaptureRequest เดียวได้ ข้อมูลโค้ดต่อไปนี้แสดงวิธีตั้งค่าเซสชันกล้องที่มีสตรีม 1 รายการสำหรับตัวอย่างภาพจากกล้องและสตรีมอีก 1 รายการสำหรับการประมวลผลรูปภาพ
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 basic 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 basic 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 ตัว ได้แก่ ประเภทเอาต์พุต ขนาดเอาต์พุต และระดับฮาร์ดแวร์
การใช้ตัวแปรที่ใช้ร่วมกันซึ่งไม่รองรับอาจทำงานที่อัตราเฟรมต่ำ หากไม่เป็นเช่นนั้น ระบบจะทริกเกอร์ Callback ที่ไม่สำเร็จรายการใดรายการหนึ่ง เอกสารประกอบสำหรับ 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) แล้วแต่ว่าค่าใดจะน้อยกว่า สัดส่วนภาพอาจไม่ตรงกับสัดส่วนภาพของหน้าจอพอดี คุณจึงอาจต้องใช้ Letterbox หรือครอบตัดสตรีมเพื่อแสดงในโหมดเต็มหน้าจอ หากต้องการได้ขนาดตัวอย่างที่เหมาะสม ให้เปรียบเทียบขนาดเอาต์พุตที่มีกับขนาดการแสดงผล โดยคำนึงว่าการแสดงผลอาจหมุนได้
โค้ดต่อไปนี้จะกำหนดคลาสตัวช่วย 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 |
JPEG |
MAXIMUM |
การจับภาพนิ่งและการประมวลผลในแอป |
LEGACY เป็นระดับฮาร์ดแวร์ต่ำสุดที่เป็นไปได้ ตารางนี้แสดงให้เห็นว่าอุปกรณ์ทุกเครื่องที่รองรับ Camera2 (ระดับ API 21 ขึ้นไป) สามารถแสดงผลสตรีมพร้อมกันได้สูงสุด 3 รายการโดยใช้การกำหนดค่าที่เหมาะสม และหากไม่มีโอเวอร์เฮดที่จำกัดประสิทธิภาพมากเกินไป เช่น ข้อจำกัดด้านหน่วยความจำ, 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 จากโมดูลทั่วไปของตัวอย่างกล้องใน GitHub ซึ่งจะกำหนดขนาดสัมบูรณ์โดยพิจารณาทั้งสัดส่วนภาพและพื้นที่ว่าง พร้อมทั้งปรับโดยอัตโนมัติเมื่อมีการทริกเกอร์การเปลี่ยนแปลงกิจกรรม
การตั้งค่าแพลตฟอร์มอื่นจาก ImageReader ด้วยรูปแบบที่เลือกจะง่ายกว่า เนื่องจากไม่ต้องรอ Callback
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