Android 10 giới thiệu các API quản lý vùng đệm camera HAL3 không bắt buộc, cho phép bạn triển khai logic quản lý vùng đệm để đạt được các điểm cân bằng khác nhau về bộ nhớ và độ trễ chụp trong quá trình triển khai camera HAL.
HAL camera yêu cầu N yêu cầu (trong đó N bằng độ sâu của quy trình) được xếp hàng đợi trong quy trình của HAL camera, nhưng thường thì HAL camera không yêu cầu tất cả N bộ đệm đầu ra cùng một lúc.
Ví dụ: HAL có thể có 8 yêu cầu được xếp hàng trong quy trình, nhưng chỉ yêu cầu các vùng đệm đầu ra cho 2 yêu cầu ở các giai đoạn cuối của quy trình. Trên các thiết bị chạy Android 9 trở xuống, khung camera sẽ phân bổ các vùng đệm khi yêu cầu được xếp hàng trong HAL, vì vậy có thể có 6 nhóm vùng đệm trong HAL không được sử dụng. Trong Android 10, các API quản lý vùng đệm HAL3 của camera cho phép tách các vùng đệm đầu ra để giải phóng 6 bộ vùng đệm. Điều này có thể giúp tiết kiệm hàng trăm megabyte bộ nhớ trên các thiết bị cao cấp, đồng thời cũng có thể mang lại lợi ích cho các thiết bị có bộ nhớ thấp.
Hình 1 cho thấy sơ đồ giao diện HAL camera cho các thiết bị chạy Android 9 trở xuống. Hình 2 minh hoạ giao diện HAL camera trong Android 10 với các API quản lý bộ đệm HAL3 camera được triển khai.
Hình 1. Giao diện HAL camera trong Android 9 trở xuống
Hình 2. Giao diện HAL camera trong Android 10 bằng cách sử dụng các API quản lý bộ đệm
Triển khai các API quản lý vùng đệm
Để triển khai các API quản lý vùng đệm, HAL máy ảnh phải:
- Triển khai HIDL
ICameraDevice@3.5
. - Đặt khoá đặc điểm của camera
android.info.supportedBufferManagementVersion
thànhHIDL_DEVICE_3_5
.
HAL camera sử dụng các phương thức requestStreamBuffers
và returnStreamBuffers
trong ICameraDeviceCallback.hal
để yêu cầu và trả về các vùng đệm. HAL cũng phải triển khai phương thức signalStreamFlush
trong ICameraDeviceSession.hal
để báo hiệu cho HAL camera trả về các vùng đệm.
requestStreamBuffers
Sử dụng phương thức requestStreamBuffers
để yêu cầu vùng đệm từ khung camera. Khi sử dụng các API quản lý bộ đệm HAL3 của camera, các yêu cầu chụp từ khung camera không chứa bộ đệm đầu ra, tức là trường bufferId
trong StreamBuffer
là 0
. Do đó, HAL camera phải sử dụng requestStreamBuffers
để yêu cầu các vùng đệm từ khung camera.
Phương thức requestStreamBuffers
cho phép phương thức gọi yêu cầu nhiều vùng đệm từ nhiều luồng đầu ra trong một lệnh gọi duy nhất, cho phép giảm số lượng lệnh gọi HIDL IPC. Tuy nhiên, các lệnh gọi sẽ mất nhiều thời gian hơn khi có nhiều vùng đệm được yêu cầu cùng lúc và điều này có thể ảnh hưởng tiêu cực đến tổng độ trễ từ yêu cầu đến kết quả.
Ngoài ra, vì các lệnh gọi vào requestStreamBuffers
được chuyển đổi tuần tự trong dịch vụ camera, nên HAL camera nên sử dụng một luồng chuyên dụng có mức độ ưu tiên cao để yêu cầu các vùng đệm.
Nếu yêu cầu vùng đệm không thành công, HAL camera phải có khả năng xử lý đúng cách các lỗi không nghiêm trọng. Danh sách sau đây mô tả các lý do phổ biến khiến yêu cầu về vùng đệm không thành công và cách HAL camera xử lý các yêu cầu đó.
- Ứng dụng ngắt kết nối khỏi luồng đầu ra:
Đây là lỗi không nghiêm trọng. HAL camera phải gửi
ERROR_REQUEST
cho mọi yêu cầu chụp ảnh nhắm đến một luồng bị ngắt kết nối và sẵn sàng xử lý các yêu cầu tiếp theo một cách bình thường. - Hết thời gian chờ: Điều này có thể xảy ra khi một ứng dụng đang bận xử lý chuyên sâu trong khi giữ lại một số vùng đệm. HAL camera phải gửi
ERROR_REQUEST
cho các yêu cầu chụp không thể thực hiện được do lỗi hết thời gian chờ và sẵn sàng xử lý các yêu cầu tiếp theo một cách bình thường. - Khung camera đang chuẩn bị một cấu hình luồng mới:
HAL camera phải đợi cho đến khi lệnh gọi
configureStreams
tiếp theo hoàn tất rồi mới gọi lạirequestStreamBuffers
. - HAL camera đã đạt đến giới hạn bộ đệm (trường
maxBuffers
): HAL camera phải đợi cho đến khi trả về ít nhất một bộ đệm của luồng trước khi gọi lạirequestStreamBuffers
.
returnStreamBuffers
Sử dụng phương thức returnStreamBuffers
để trả về các vùng đệm bổ sung cho khung camera. HAL camera thường trả về các vùng đệm cho khung camera thông qua phương thức processCaptureResult
, nhưng chỉ có thể tính đến những yêu cầu chụp đã được gửi đến HAL camera. Với phương thức requestStreamBuffers
, việc triển khai HAL camera có thể giữ lại nhiều vùng đệm hơn so với những gì mà khung camera đã yêu cầu. Đây là thời điểm bạn nên sử dụng phương thức returnStreamBuffers
. Nếu quá trình triển khai HAL không bao giờ giữ nhiều bộ đệm hơn mức yêu cầu, thì quá trình triển khai HAL của camera không cần gọi phương thức returnStreamBuffers
.
signalStreamFlush
Phương thức signalStreamFlush
được khung camera gọi để thông báo cho HAL camera trả về tất cả các vùng đệm hiện có. Thao tác này thường được gọi khi khung máy ảnh sắp gọi configureStreams
và phải xả hết quy trình chụp ảnh. Tương tự như phương thức returnStreamBuffers
, nếu một quy trình triển khai HAL camera không giữ nhiều vùng đệm hơn mức được yêu cầu, thì bạn có thể có một quy trình triển khai trống của phương thức này.
Sau khi khung camera gọi signalStreamFlush
, khung sẽ ngừng gửi các yêu cầu chụp mới đến HAL camera cho đến khi tất cả các vùng đệm được trả về khung camera. Khi tất cả các vùng đệm được trả về, phương thức requestStreamBuffers
sẽ không gọi được và khung camera có thể tiếp tục hoạt động ở trạng thái mới. Sau đó, khung camera sẽ gọi phương thức configureStreams
hoặc processCaptureRequest
. Nếu khung camera gọi phương thức configureStreams
, thì HAL camera có thể bắt đầu yêu cầu lại các vùng đệm sau khi lệnh gọi configureStreams
trả về thành công. Nếu khung camera gọi phương thức processCaptureRequest
, HAL camera có thể bắt đầu yêu cầu các vùng đệm trong lệnh gọi processCaptureRequest
.
Ngữ nghĩa của phương thức signalStreamFlush
và phương thức flush
là khác nhau. Khi phương thức flush
được gọi, HAL có thể huỷ các yêu cầu chụp đang chờ xử lý bằng ERROR_REQUEST
để xả hết quy trình càng sớm càng tốt. Khi phương thức signalStreamFlush
được gọi, HAL phải hoàn tất tất cả các yêu cầu chụp đang chờ xử lý một cách bình thường và trả về tất cả các vùng đệm cho khung camera.
Một điểm khác biệt nữa giữa phương thức signalStreamFlush
và các phương thức khác là signalStreamFlush
là một phương thức HIDL một chiều, nghĩa là khung camera có thể gọi vào các API chặn khác trước khi HAL nhận được lệnh gọi signalStreamFlush
. Điều này có nghĩa là phương thức signalStreamFlush
và các phương thức khác (cụ thể là phương thức configureStreams
) có thể đến HAL camera theo thứ tự khác với thứ tự mà chúng được gọi trong khung camera. Để giải quyết vấn đề không đồng bộ này, trường streamConfigCounter
đã được thêm vào StreamConfiguration
và được thêm dưới dạng một đối số vào phương thức signalStreamFlush
. Quá trình triển khai HAL camera phải sử dụng đối số streamConfigCounter
để xác định xem lệnh gọi signalStreamFlush
có đến muộn hơn lệnh gọi configureStreams
tương ứng hay không. Hãy xem Hình 3 để biết ví dụ.
Hình 3. Cách HAL camera phát hiện và xử lý các lệnh gọi signalStreamFlush đến muộn
Các thay đổi về hành vi khi triển khai API quản lý vùng đệm
Khi sử dụng các API quản lý vùng đệm để triển khai logic quản lý vùng đệm, hãy cân nhắc những thay đổi có thể xảy ra về hành vi đối với camera và việc triển khai HAL camera:
Yêu cầu chụp ảnh đến HAL máy ảnh nhanh hơn và thường xuyên hơn: Nếu không có API quản lý bộ đệm, khung máy ảnh sẽ yêu cầu bộ đệm đầu ra cho mỗi yêu cầu chụp ảnh trước khi gửi yêu cầu chụp ảnh đến HAL máy ảnh. Khi sử dụng API quản lý bộ nhớ đệm, khung camera không còn cần phải đợi bộ nhớ đệm nữa và do đó có thể gửi các yêu cầu chụp đến HAL camera sớm hơn.
Ngoài ra, nếu không có API quản lý bộ nhớ đệm, khung camera sẽ ngừng gửi yêu cầu chụp nếu một trong các luồng đầu ra của yêu cầu chụp đã đạt đến số lượng bộ nhớ đệm tối đa mà HAL có thể giữ cùng một lúc (giá trị này do HAL camera chỉ định trong trường
HalStream::maxBuffers
trong giá trị trả về của lệnh gọiconfigureStreams
). Với các API quản lý vùng đệm, hành vi điều tiết này không còn tồn tại và quá trình triển khai HAL camera không được chấp nhận các lệnh gọiprocessCaptureRequest
khi HAL có quá nhiều yêu cầu chụp được xếp hàng.requestStreamBuffers
độ trễ cuộc gọi có sự khác biệt đáng kể: Có nhiều lý do khiến cuộc gọirequestStreamBuffers
có thể mất nhiều thời gian hơn mức trung bình. Ví dụ:- Đối với một vài vùng đệm đầu tiên của luồng mới tạo, các lệnh gọi có thể mất nhiều thời gian hơn vì thiết bị cần phân bổ bộ nhớ.
- Độ trễ dự kiến tăng tỷ lệ thuận với số lượng vùng đệm được yêu cầu trong mỗi lệnh gọi.
- Ứng dụng đang giữ các vùng đệm và đang bận xử lý. Điều này có thể khiến các yêu cầu về vùng đệm bị chậm hoặc hết thời gian chờ do thiếu vùng đệm hoặc CPU bận.
Chiến lược quản lý bộ đệm
Các API quản lý vùng đệm cho phép triển khai nhiều loại chiến lược quản lý vùng đệm. Dưới đây là một số ví dụ:
- Tương thích ngược: HAL yêu cầu các vùng đệm cho một yêu cầu chụp trong lệnh gọi
processCaptureRequest
. Chiến lược này không giúp tiết kiệm bộ nhớ, nhưng có thể đóng vai trò là cách triển khai đầu tiên của các API quản lý vùng đệm, chỉ yêu cầu rất ít thay đổi về mã đối với HAL camera hiện có. - Tiết kiệm tối đa bộ nhớ: HAL máy ảnh chỉ yêu cầu các vùng đệm đầu ra ngay trước khi cần điền một vùng đệm. Chiến lược này giúp bạn tiết kiệm bộ nhớ tối đa. Nhược điểm tiềm ẩn là đường dẫn camera bị giật nhiều hơn khi các yêu cầu về vùng đệm mất quá nhiều thời gian để hoàn tất.
- Đã lưu vào bộ nhớ đệm: HAL camera lưu vào bộ nhớ đệm một số vùng đệm để ít bị ảnh hưởng bởi yêu cầu vùng đệm chậm không thường xuyên.
HAL camera có thể áp dụng các chiến lược khác nhau cho những trường hợp sử dụng cụ thể, chẳng hạn như sử dụng chiến lược tiết kiệm bộ nhớ tối đa cho những trường hợp sử dụng nhiều bộ nhớ và sử dụng chiến lược tương thích ngược cho những trường hợp sử dụng khác.
Phương thức triển khai mẫu trong HAL camera bên ngoài
HAL camera bên ngoài được giới thiệu trong Android 9 và có thể tìm thấy trong cây nguồn tại hardware/interfaces/camera/device/3.5/
.
Trong Android 10, API này đã được cập nhật để bao gồm ExternalCameraDeviceSession.cpp
, một cách triển khai API quản lý vùng đệm. HAL camera bên ngoài này triển khai chiến lược tối đa hoá mức tiết kiệm bộ nhớ được đề cập trong Chiến lược quản lý vùng đệm trong vài trăm dòng mã C++.