API quản lý vùng đệm Camera HAL3

Android 10 giới thiệu các API quản lý bộ đệm HAL3 cho camera không bắt buộc . Các API này cho phép bạn triển khai logic quản lý bộ đệ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 HAL cho camera .

HAL cho camera yêu cầu N yêu cầu (trong đó N bằng với độ sâu của quy trình) được xếp hàng đợi trong quy trình của nó, nhưng thường thì 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 đợi trong quy trình, nhưng chỉ yêu cầu bộ đệ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ổ bộ đệm khi yêu cầu được xếp hàng đợi trong HAL, vì vậy có thể có 6 bộ đệm trong HAL không được sử dụng. Trong Android 10, các API quản lý bộ đệm HAL3 cho camera cho phép tách các bộ đệm đầu ra để giải phóng 6 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 cho thấy sơ đồ giao diện HAL cho camera đối với các thiết bị chạy Android 9 trở xuống. Hình 2 cho thấy giao diện HAL cho camera trong Android 10 với các API quản lý bộ đệm HAL3 cho camera được triển khai.

Quản lý bộ nhớ đệm trong Android 9 trở xuống

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

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

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

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

Để triển khai các API quản lý bộ đệm, HAL cho camera phải:

HAL cho camera 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 cho HAL cho camera trả về bộ đệm.

requestStreamBuffers

Sử dụng phương thức requestStreamBuffers để yêu cầu bộ đệm từ khung camera. Khi sử dụng các API quản lý bộ đệm HAL3 cho 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 StreamBuffer0. Do đó, HAL cho camera phải sử dụng requestStreamBuffers để yêu cầu bộ đệm từ khung camera.

Phương thức requestStreamBuffers cho phép trình gọi yêu cầu nhiều bộ đệm từ nhiều luồng đầu ra trong một lệnh gọi, cho phép ít lệnh gọi HIDL IPC hơn. Tuy nhiên, các lệnh gọi sẽ mất nhiều thời gian hơn khi nhiều bộ đệm được yêu cầu cùng một 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ự hoá trong dịch vụ camera, nên bạn nên để HAL cho camera sử dụng một luồng ưu tiên cao riêng để yêu cầu bộ đệm.

Nếu yêu cầu bộ đệm không thành công, HAL cho 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 thường gặp khiến yêu cầu bộ đệm không thành công và cách HAL cho camera nên 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 cho camera phải gửi ERROR_REQUEST cho mọi yêu cầu chụp nhắm đến một luồng đã 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ữ một số bộ đệm. HAL cho 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 cho camera phải đợi cho đến khi configureStreams tiếp theo hoàn tất rồi mới gọi lại requestStreamBuffers lần nữa.
  • HAL cho camera đã đạt đến giới hạn bộ đệm (trường maxBuffers): HAL cho camera phải đợi cho đến khi trả về ít nhất một bộ đệm của luồng rồi mới gọi lại requestStreamBuffers.

returnStreamBuffers

Sử dụng phương thức để trả về bộ đệm bổ sung cho khung camera.returnStreamBuffers HAL cho camera thường trả về bộ đệm cho khung camera thông qua processCaptureResult phương thức, nhưng chỉ có thể tính đến các yêu cầu chụp đã được gửi đến HAL cho camera. Với phương thức requestStreamBuffers, việc triển khai HAL cho camera có thể giữ lại nhiều bộ đệm hơn so với những gì đã được 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 cho 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 cho camera trả về tất cả bộ đệm hiện có. Phương thức này thường được gọi khi khung camera sắp gọi configureStreams và phải làm trống quy trình chụp của camera. Tương tự như phương thức returnStreamBuffers, nếu quá trình triển khai HAL cho camera không giữ nhiều bộ đệm hơn mức yêu cầu, thì bạn có thể triển khai phương thức này ở trạng thái trống.

Sau khi khung camera gọi signalStreamFlush, khung này sẽ ngừng gửi các yêu cầu chụp mới đến HAL cho camera cho đến khi tất cả bộ đệm được trả về khung camera. Khi tất cả bộ đệm được trả về, các lệnh gọi phương thức requestStreamBuffers sẽ không thành công và khung camera có thể tiếp tục hoạt động ở trạng thái sạch. 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 cho camera 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 camera gọi phương thức processCaptureRequest, thì HAL cho camera có thể bắt đầu yêu cầu bộ đệm trong lệnh gọi processCaptureRequest.

Ngữ nghĩa khác nhau đối với phương thức signalStreamFlush và phương thức flush. 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 để làm trống 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ả bộ đệ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à phương thức HIDL một chiều. Điều này có nghĩa là khung camera có thể gọ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 cho 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 làm đối số cho phương thức signalStreamFlush. Quá trình triển khai HAL cho 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ụ.

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

Hình 3. Cách HAL cho 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 các API quản lý bộ đệm

Khi sử dụng các API quản lý bộ đệm để triển khai logic quản lý bộ đệm, hãy cân nhắc các thay đổi có thể xảy ra về hành vi đối với camera và quá trình triển khai HAL cho camera:

  • Các yêu cầu chụp đến HAL cho camera nhanh hơn và thường xuyên hơn: Nếu không có các API quản lý bộ đệm, khung camera sẽ yêu cầu bộ đệm đầu ra cho từng yêu cầu chụp trước khi gửi yêu cầu chụp đến HAL cho camera. Khi sử dụng các API quản lý bộ đệm, khung camera không cần phải đợi bộ đệm nữa và do đó có thể gửi các yêu cầu chụp đến HAL cho camera sớm hơn.

    Ngoài ra, nếu không có các API quản lý bộ đệm, khung camera sẽ ngừng gửi các 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 HAL cho camera chỉ định 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 tiết này không còn tồn tại và quá trình triển khai HAL cho camera 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ễ của lệnh gọi requestStreamBuffers thay đổi đáng kể: Có nhiều lý do khiến lệnh 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 vài bộ đệ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 bộ đệm được yêu cầu trong mỗi lệnh 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 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

Các API quản lý bộ đệm cho phép triển khai nhiều loại chiến lược quản lý bộ đệm. Dưới đây là một số ví dụ:

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

HAL cho camera 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 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 cho camera bên ngoài

HAL cho 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, HAL này đã được cập nhật để bao gồm ExternalCameraDeviceSession.cpp, một quá trình triển khai API quản lý bộ đệm. HAL cho camera bên ngoài này triển khai chiến lược tiết kiệm bộ nhớ tối đa được đề cập trong phần Chiến lược quản lý bộ đệm trong vài trăm dòng mã C++.