API quản lý bộ đệm HAL3 của máy ảnh

Android 10 giới thiệu các API quản lý bộ đệm HAL3 của máy ảnh tùy chọn cho phép bạn triển khai logic quản lý bộ đệm để đạt được sự cân bằng về bộ nhớ và độ trễ ghi khác nhau trong quá trình triển khai HAL của máy ảnh.

HAL của máy ảnh yêu cầu N yêu cầu (trong đó N bằng độ sâu đường ống ) được xếp hàng đợi trong đường ống của nó, nhưng nó thường không yêu cầu tất cả N bộ bộ đệm đầu ra cùng một lúc.

Ví dụ: HAL có thể có tám yêu cầu được xếp hàng đợi trong đường ống, nhưng nó chỉ yêu cầu bộ đệm đầu ra cho hai yêu cầu ở giai đoạn cuối của đường ống. Trên các thiết bị chạy Android 9 trở xuống, khung máy ảnh sẽ phân bổ bộ đệm khi yêu cầu được xếp hàng đợi trong HAL, do đó có thể có sáu bộ bộ đệm trong HAL không được sử dụng. Trong Android 10, API quản lý bộ đệm HAL3 của máy ảnh cho phép tách bộ đệm đầu ra để giải phóng sáu bộ bộ đệ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 và cũng có thể có lợi cho các thiết bị có bộ nhớ thấp.

Hình 1 hiển thị sơ đồ giao diện HAL của camera dành cho các thiết bị chạy Android 9 trở xuống. Hình 2 hiển thị giao diện HAL của camera trong Android 10 với API quản lý bộ đệm HAL3 của camera được triển khai.

Quản lý bộ đệm trong 9 hoặc thấp hơn

Hình 1. Giao diện Camera HAL trong Android 9 trở xuống

Quản lý bộ đệm trong Android 10

Hình 2. Giao diện Camera HAL trong Android 10 sử dụng API quản lý bộ đệm

Triển khai API quản lý bộ đệm

Để triển khai API quản lý bộ đệm, HAL của máy ảnh phải:

HAL máy ảnh sử dụng các phương thức requestStreamBuffersreturnStreamBuffers trong ICameraDeviceCallback.hal để yêu cầu và trả về bộ đệm. HAL cũng phải triển khai phương thức signalStreamFlush trong ICameraDeviceSession.hal để báo hiệu HAL của máy ảnh trả về bộ đệm.

requestStreamBuffers

Sử dụng phương thức requestStreamBuffers để yêu cầu bộ đệm từ khung máy ảnh. Khi sử dụng API quản lý bộ đệm HAL3 của máy ảnh, các yêu cầu chụp từ khung máy ảnh không chứa bộ đệm đầu ra, nghĩa là trường bufferId trong StreamBuffer0 . Do đó, HAL của máy ảnh phải sử dụng requestStreamBuffers để yêu cầu bộ đệm từ khung máy ảnh.

Phương thức requestStreamBuffers cho phép người gọi yêu cầu nhiều bộ đệm từ nhiều luồng đầu ra trong một cuộc gọi, cho phép thực hiện ít cuộc gọi HIDL IPC hơn. Tuy nhiên, các cuộc gọi sẽ mất nhiều thời gian hơn khi yêu cầu nhiều bộ đệm hơn 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 tuần tự hóa trong dịch vụ máy ảnh nên HAL của máy ảnh nên sử dụng một luồng chuyên dụng có mức độ ưu tiên cao để yêu cầu bộ đệm.

Nếu yêu cầu bộ đệm không thành công, HAL của máy ảnh phải có khả năng xử lý đúng 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 bộ đệm không thành công và cách HAL camera xử lý chúng.

  • Ứ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. Máy ảnh HAL sẽ gửi ERROR_REQUEST cho bất kỳ yêu cầu chụp nào nhắm mục tiêu 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 vẫn giữ một số bộ đệm. Máy ảnh HAL sẽ 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 máy ảnh đang chuẩn bị cấu hình luồng mới: HAL máy ảnh phải đợi cho đến khi lệnh gọi configureStreams tiếp theo hoàn tất trước khi gọi lại requestStreamBuffers .
  • HAL của máy ảnh đã đạt đến giới hạn bộ đệm (trường maxBuffers ): HAL của máy ảnh phải đợi cho đến khi nó trả về ít nhất một bộ đệm của luồng trước khi gọi lại requestStreamBuffers .

returnStreamBuffers

Sử dụng phương thức returnStreamBuffers để trả về bộ đệm bổ sung cho khung máy ảnh. Máy ảnh HAL thường trả về bộ đệm cho khung máy ảnh thông qua phương thức processCaptureResult , nhưng nó chỉ có thể giải quyết các yêu cầu chụp đã được gửi đến máy ảnh HAL. Với phương thức requestStreamBuffers , việc triển khai HAL của máy ảnh có thể giữ lại nhiều bộ đệm hơn những gì khung máy ảnh yêu cầu. Đây là lúc nên sử dụng phương thức returnStreamBuffers . Nếu việc triển khai HAL không bao giờ chứa nhiều bộ đệm hơn yêu cầu thì việc triển khai HAL của máy ảnh không cần gọi phương thức returnStreamBuffers .

tín hiệuStreamFlush

Phương thức signalStreamFlush được khung máy ảnh gọi để thông báo cho máy ảnh HAL trả lại tất cả các bộ đệm có sẵn. Điều này thường được gọi khi khung máy ảnh sắp gọi configureStreams và phải thoát khỏi đường dẫn chụp ảnh. Tương tự như phương thức returnStreamBuffers , nếu việc triển khai HAL của máy ảnh không chứa nhiều bộ đệm hơn yêu cầu thì có thể triển khai phương thức này trống.

Sau khi khung máy ảnh gọi signalStreamFlush , khung sẽ dừng gửi yêu cầu chụp mới tới HAL của máy ảnh cho đến khi tất cả bộ đệm được trả về khung máy ảnh. Khi tất cả bộ đệm được trả về, lệnh gọi phương thức requestStreamBuffers không thành công và khung máy ảnh có thể tiếp tục hoạt động ở trạng thái sạch. Sau đó, khung máy ảnh sẽ gọi phương thức configureStreams hoặc processCaptureRequest . Nếu khung máy ảnh gọi phương thức configureStreams , HAL của máy ảnh có thể bắt đầu yêu cầu lại bộ đệm sau khi lệnh gọi configureStreams trả về thành công. Nếu khung máy ảnh gọi phương thức processCaptureRequest thì HAL của máy ảnh có thể bắt đầu yêu cầu bộ đệ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ể hủy bỏ các yêu cầu chụp đang chờ xử lý bằng ERROR_REQUEST để thoát khỏi đường ống càng sớm càng tốt. Khi phương thức signalStreamFlush được gọi, HAL phải hoàn thành 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ả lại tất cả bộ đệm cho khung máy ảnh.

Một điểm khác biệt giữa phương thức signalStreamFlush và các phương thức khác là signalStreamFlush là phương thức HIDL một chiều , có nghĩa là khung máy ảnh có thể gọi tới 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 của máy ảnh theo thứ tự khác với thứ tự chúng được gọi trong khung máy ảnh. Để 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 làm đối số cho phương thức signalStreamFlush . Việc triển khai HAL của máy ảnh nên sử dụng đối 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. Xem Hình 3 để biết ví dụ.

Xử lý các cuộc gọi đến muộn

Hình 3. Cách HAL của camera phát hiện và xử lý các cuộc gọi signalStreamFlush đến muộn

Thay đổi hành vi khi triển khai API quản lý bộ đệm

Khi sử dụng API quản lý bộ đệm để triển khai logic quản lý bộ đệm, hãy xem xét các thay đổi hành vi có thể xảy ra sau đây đối với việc triển khai HAL của máy ảnh và máy ảnh:

  • Yêu cầu chụp đến HAL của 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 trước khi gửi yêu cầu chụp đến máy ảnh HAL. Khi sử dụng API quản lý bộ đệm, khung máy ảnh không còn cần phải chờ bộ đệm nữa và do đó có thể gửi yêu cầu chụp tới máy ảnh HAL sớm hơn.

    Ngoài ra, nếu không có API quản lý bộ đệm, khung máy ảnh 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ộ đệm tối đa mà HAL có thể giữ cùng một lúc (giá trị này được chỉ định bởi máy ảnh HAL trong Trường HalStream::maxBuffers trong giá trị trả về của lệnh gọi configureStreams ). Với các API quản lý bộ đệm, hành vi điều chỉnh này không còn tồn tại và việc triển khai HAL của máy ảnh không được chấp nhận các lệnh gọi processCaptureRequest khi HAL có quá nhiều yêu cầu chụp được xếp hàng đợi.

  • Độ trễ cuộc gọi requestStreamBuffers thay đổi đáng kể: Có nhiều lý do khiến cuộc gọi requestStreamBuffers có thể mất nhiều thời gian hơn mức trung bình. Ví dụ:

    • Đối với một số bộ đệm đầu tiên của luồng mới được tạo, cuộc 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 bộ đệm được yêu cầu trong mỗi cuộc gọi.
    • Ứng dụng đang giữ bộ đệm và đang bận xử lý. Điều này có thể khiến các yêu cầu bộ đệm bị chậm lại hoặc hết thời gian chờ do thiếu bộ đệm hoặc CPU bận.

Chiến lược quản lý bộ đệm

API quản lý bộ đệm cho phép triển khai các loại chiến lược quản lý bộ đệm khác nhau. Một số ví dụ:

  • Tương thích ngược: HAL yêu cầu bộ đệm cho 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à lần triển khai đầu tiên của API quản lý bộ đệm, yêu cầu rất ít thay đổi mã đối với HAL máy ảnh hiện có.
  • Tiết kiệm bộ nhớ tối đa: HAL của máy ảnh chỉ yêu cầu bộ đệm đầu ra ngay trước khi cần lấp đầy bộ đệm. Chiến lược này cho phép tiết kiệm bộ nhớ tối đa. Nhược điểm tiềm ẩn là đường ống camera bị giật nhiều hơn khi các yêu cầu bộ đệm mất nhiều thời gian để hoàn thành.
  • Đã lưu vào bộ nhớ đệm: HAL của máy ảnh lưu vào bộ nhớ đệm một số bộ đệm để ít có khả năng bị ảnh hưởng bởi yêu cầu bộ đệm chậm thường xuyên.

HAL máy ảnh có thể áp dụng các chiến lược khác nhau cho các trường hợp sử dụng cụ thể, ví dụ: sử dụng chiến lược tiết kiệm bộ nhớ tối đa cho các trường hợp sử dụng sử dụng nhiều bộ nhớ và sử dụng chiến lược tương thích ngược cho các trường hợp sử dụng khác.

Triển khai mẫu trong HAL camera bên ngoài

Máy ảnh bên ngoài HAL đã được giới thiệu trong Android 9 và có thể được tìm thấy trong cây nguồn tại hardware/interfaces/camera/device/3.5/ . Trong Android 10, nó đã được cập nhật để bao gồm ExternalCameraDeviceSession.cpp , một triển khai API quản lý bộ đệm. Camera ngoài HAL này triển khai chiến lược tiết kiệm bộ nhớ tối đa được đề cập trong chiến lược quản lý bộ đệm trong vài trăm dòng mã C++.