Bản xem trước của camera

Lưu ý: Trang này đề cập đến gói Camera2. Bạn nên sử dụng CameraX, trừ phi ứng dụng của bạn yêu cầu các tính năng cụ thể, cấp thấp của Camera2. Cả CameraX và Camera2 đều hỗ trợ Android 5.0 (API cấp 21) trở lên.

Không phải lúc nào máy ảnh và bản xem trước của máy ảnh cũng có cùng hướng trên thiết bị Android.

Máy ảnh nằm ở một vị trí cố định trên thiết bị, bất kể thiết bị đó là điện thoại, máy tính bảng hay máy tính. Khi hướng thiết bị thay đổi, hướng camera cũng thay đổi.

Do đó, các ứng dụng máy ảnh thường giả định mối quan hệ cố định giữa hướng của thiết bị và tỷ lệ khung hình của bản xem trước máy ảnh. Khi điện thoại ở hướng dọc, bản xem trước của máy ảnh được giả định là có chiều cao lớn hơn chiều rộng. Khi điện thoại (và máy ảnh) được xoay sang ngang, bản xem trước của máy ảnh sẽ có chiều rộng lớn hơn chiều cao.

Tuy nhiên, những giả định này đang bị thách thức bởi các kiểu dáng mới, chẳng hạn như thiết bị có thể gập lại và các chế độ hiển thị như nhiều cửa sổ và nhiều màn hình. Thiết bị gập thay đổi kích thước hiển thị và tỷ lệ khung hình mà không thay đổi hướng. Chế độ nhiều cửa sổ giới hạn các ứng dụng máy ảnh ở một phần màn hình, điều chỉnh tỷ lệ bản xem trước của máy ảnh bất kể hướng thiết bị. Chế độ nhiều màn hình cho phép sử dụng màn hình phụ có thể không cùng hướng với màn hình chính.

Hướng máy ảnh

Định nghĩa về khả năng tương thích với Android chỉ rõ rằng cảm biến hình ảnh của máy ảnh "PHẢI được định hướng để chiều dài của máy ảnh phù hợp với chiều dài của màn hình". Tức là khi thiết bị được giữ theo hướng ngang, máy ảnh PHẢI chụp ảnh theo hướng ngang. Điều này áp dụng bất kể hướng tự nhiên của thiết bị; tức là áp dụng cho cả thiết bị có hướng chính là ngang và thiết bị có hướng chính là dọc."

Cách sắp xếp camera theo màn hình giúp tối đa hoá vùng hiển thị của kính ngắm camera trong ứng dụng camera. Ngoài ra, cảm biến hình ảnh thường xuất dữ liệu theo tỷ lệ khung hình ngang, trong đó 4:3 là tỷ lệ phổ biến nhất.

Cả điện thoại và cảm biến camera đều ở hướng dọc.
Hình 1. Mối quan hệ điển hình giữa hướng của điện thoại và cảm biến máy ảnh.

Hướng tự nhiên của cảm biến máy ảnh là hướng ngang. Trong hình 1, cảm biến của máy ảnh trước (máy ảnh hướng về cùng một hướng với màn hình) được xoay 270 độ so với điện thoại để tuân thủ Định nghĩa về khả năng tương thích với Android.

Để hiển thị chế độ xoay cảm biến cho các ứng dụng, API camera2 bao gồm một hằng số SENSOR_ORIENTATION. Đối với hầu hết điện thoại và máy tính bảng, thiết bị sẽ báo cáo hướng cảm biến là 270 độ cho camera trước và 90 độ (góc nhìn từ phía sau thiết bị) cho camera sau, giúp căn chỉnh cạnh dài của cảm biến với cạnh dài của thiết bị. Máy ảnh của máy tính xách tay thường báo cáo hướng cảm biến là 0 hoặc 180 độ.

Vì cảm biến hình ảnh của máy ảnh xuất dữ liệu (vùng đệm hình ảnh) theo hướng tự nhiên của cảm biến (ngang), nên vùng đệm hình ảnh phải được xoay theo số độ do SENSOR_ORIENTATION chỉ định để bản xem trước của máy ảnh xuất hiện theo hướng thẳng đứng trong hướng tự nhiên của thiết bị. Đối với camera trước, góc xoay là ngược chiều kim đồng hồ; đối với camera sau, góc xoay là theo chiều kim đồng hồ.

Ví dụ: đối với camera trước trong hình 1, vùng đệm hình ảnh do cảm biến camera tạo ra sẽ có dạng như sau:

Cảm biến máy ảnh xoay sang hướng ngang với hình ảnh
            theo chiều ngang, trên cùng bên trái.
Hình 2. Vùng đệm hình ảnh thô từ cảm biến camera trước theo hướng ngang tự nhiên.

Bạn phải xoay hình ảnh 270 độ ngược chiều kim đồng hồ để hướng của bản xem trước khớp với hướng của thiết bị:

Cảm biến máy ảnh theo hướng dọc với hình ảnh thẳng đứng.
Hình 3. Vùng đệm hình ảnh của camera trước được xoay 270 độ ngược chiều kim đồng hồ để khớp với hướng dọc của thiết bị.

Camera sau sẽ tạo ra một vùng đệm hình ảnh có cùng hướng với vùng đệm trước đó, nhưng SENSOR_ORIENTATION là 90 độ. Do đó, vùng đệm được xoay 90 độ theo chiều kim đồng hồ.

Xoay thiết bị

Độ xoay thiết bị là số độ mà thiết bị được xoay so với hướng tự nhiên. Ví dụ: điện thoại theo hướng ngang có góc xoay thiết bị là 90 hoặc 270 độ, tuỳ thuộc vào hướng xoay.

Bộ đệm hình ảnh của cảm biến máy ảnh phải được xoay cùng số độ với độ xoay của thiết bị (ngoài số độ của hướng cảm biến) để bản xem trước của máy ảnh xuất hiện theo chiều thẳng đứng.

Tính toán hướng

Hướng thích hợp của bản xem trước máy ảnh sẽ xem xét hướng cảm biến và độ xoay thiết bị.

Bạn có thể tính toán độ xoay tổng thể của vùng đệm hình ảnh cảm biến bằng công thức sau:

rotation = (sensorOrientationDegrees - deviceOrientationDegrees * sign + 360) % 360

trong đó sign là 1 đối với camera trước, -1 đối với camera sau.

Đối với camera trước, vùng đệm hình ảnh được xoay ngược chiều kim đồng hồ (từ hướng tự nhiên của cảm biến). Đối với camera sau, vùng đệm hình ảnh của cảm biến sẽ được xoay theo chiều kim đồng hồ.

Biểu thức deviceOrientationDegrees * sign + 360 chuyển đổi góc xoay của thiết bị từ ngược chiều kim đồng hồ sang theo chiều kim đồng hồ cho camera sau (ví dụ: chuyển đổi 270 độ ngược chiều kim đồng hồ thành 90 độ theo chiều kim đồng hồ). Phép toán modulo điều chỉnh kết quả thành dưới 360 độ (ví dụ: điều chỉnh góc xoay 540 độ thành 180 độ).

Các API khác nhau báo cáo chế độ xoay thiết bị theo cách khác nhau:

  • Display#getRotation() cung cấp góc xoay ngược chiều kim đồng hồ của thiết bị (theo góc nhìn của người dùng). Giá trị này được đưa vào công thức trước đó.
  • OrientationEventListener#onOrientationChanged() trả về góc xoay theo chiều kim đồng hồ của thiết bị (theo góc nhìn của người dùng). Phủ định giá trị để sử dụng trong công thức trước đó.

Camera trước

Cả bản xem trước và cảm biến của máy ảnh đều ở hướng ngang, cảm biến
            ở hướng thẳng đứng.
Hình 4. Bản xem trước và cảm biến của máy ảnh khi điện thoại xoay 90 độ sang hướng ngang.

Dưới đây là vùng đệm hình ảnh do cảm biến máy ảnh tạo ra trong hình 4:

Tính năng cảm biến của camera ở hướng ngang với hình ảnh thẳng đứng.
Hình 5. Vùng đệm hình ảnh do cảm biến camera trước tạo ra khi điện thoại được xoay 90 độ ngược chiều kim đồng hồ.

Vùng đệm phải được xoay 270 độ ngược chiều kim đồng hồ để điều chỉnh theo hướng cảm biến (xem phần Hướng máy ảnh ở trên):

Cảm biến máy ảnh xoay theo hướng dọc với hình ảnh nằm ngang,
            trên cùng bên phải.
Hình 6. Vùng đệm hình ảnh được xoay 270 độ ngược chiều kim đồng hồ để điều chỉnh theo hướng cảm biến.

Sau đó, vùng đệm được xoay thêm 90 độ ngược chiều kim đồng hồ để tính đến việc xoay thiết bị, dẫn đến hướng chính xác của bản xem trước máy ảnh trong hình 4:

Cảm biến máy ảnh được xoay sang hướng ngang với hình ảnh thẳng đứng.
Hình 7. Vùng đệm hình ảnh sau khi xoay thêm 90 độ ngược chiều kim đồng hồ theo hướng thiết bị.

Dưới đây là camera được xoay sang phải theo hướng ngang:

Cả bản xem trước của máy ảnh và cảm biến đều ở hướng ngang, nhưng cảm biến bị lộn ngược.
Hình 8. Bản xem trước và cảm biến của máy ảnh khi điện thoại xoay 270 độ (hoặc -90 độ) sang hướng ngang.

Sau đây là vùng đệm hình ảnh:

Cảm biến máy ảnh được xoay theo hướng ngang với hình ảnh lộn ngược.
Hình 9. Vùng đệm hình ảnh do cảm biến camera trước tạo ra khi điện thoại được xoay 270 độ ngược chiều kim đồng hồ.

Vùng đệm phải được xoay 270 độ ngược chiều kim đồng hồ để điều chỉnh theo hướng cảm biến:

Cảm biến máy ảnh xoay theo hướng dọc với hình ảnh nằm ngang,
            trên cùng bên trái.
Hình 10. Vùng đệm hình ảnh được xoay 270 độ ngược chiều kim đồng hồ để điều chỉnh theo hướng cảm biến.

Sau đó, vùng đệm được xoay thêm 270 độ ngược chiều kim đồng hồ để tính đến việc xoay thiết bị:

Cảm biến máy ảnh được xoay sang hướng ngang với hình ảnh thẳng đứng.
Hình 11. Vùng đệm hình ảnh sau khi xoay thêm 270 độ ngược chiều kim đồng hồ cho hướng thiết bị.

Camera sau

Máy ảnh mặt sau thường có hướng cảm biến là 90 độ (khi nhìn từ mặt sau của thiết bị). Khi định hướng bản xem trước của máy ảnh, vùng đệm hình ảnh cảm biến sẽ được xoay theo chiều kim đồng hồ theo mức độ xoay cảm biến (thay vì ngược chiều kim đồng hồ như máy ảnh trước), sau đó vùng đệm hình ảnh sẽ được xoay ngược chiều kim đồng hồ theo mức độ xoay thiết bị.

Cả bản xem trước của máy ảnh và cảm biến đều ở hướng ngang, nhưng cảm biến bị lộn ngược.
Hình 12. Điện thoại có camera sau theo hướng ngang (xoay 270 hoặc -90 độ).

Dưới đây là vùng đệm hình ảnh từ cảm biến camera trong hình 12:

Cảm biến máy ảnh được xoay theo hướng ngang với hình ảnh lộn ngược.
Hình 13. Vùng đệm hình ảnh do cảm biến camera sau tạo ra khi điện thoại ở hướng ngang.

Bạn phải xoay vùng đệm 90 độ theo chiều kim đồng hồ để điều chỉnh hướng cảm biến:

Cảm biến máy ảnh xoay theo hướng dọc với hình ảnh nằm ngang,
            trên cùng bên trái.
Hình 14. Vùng đệm hình ảnh được xoay 90 độ theo chiều kim đồng hồ để điều chỉnh theo hướng cảm biến mặt sau.

Sau đó, vùng đệm được xoay 270 độ ngược chiều kim đồng hồ để tính đến chế độ xoay thiết bị:

Cảm biến máy ảnh được xoay sang hướng ngang với hình ảnh thẳng đứng.
Hình 15. Vùng đệm hình ảnh sau khi xoay 270 độ ngược chiều kim đồng hồ theo hướng của thiết bị.

Tỷ lệ khung hình

Tỷ lệ khung hình hiển thị thay đổi khi hướng thiết bị thay đổi, nhưng cũng thay đổi khi thiết bị có thể gập lại gập và mở, khi cửa sổ được đổi kích thước trong môi trường nhiều cửa sổ và khi ứng dụng mở trên màn hình phụ.

Vùng đệm hình ảnh của cảm biến máy ảnh phải được định hướng và điều chỉnh tỷ lệ cho phù hợp với hướng và tỷ lệ khung hình của phần tử giao diện người dùng của kính ngắm khi giao diện người dùng thay đổi hướng một cách linh động, bất kể thiết bị có thay đổi hướng hay không.

Trên các kiểu dáng mới hoặc trong môi trường nhiều cửa sổ hoặc nhiều màn hình, nếu ứng dụng của bạn giả định rằng bản xem trước của máy ảnh có cùng hướng với thiết bị (dọc hoặc ngang), thì bản xem trước có thể bị định hướng không chính xác, điều chỉnh tỷ lệ không chính xác hoặc cả hai.

Thiết bị có thể gập lại ở trạng thái mở ra với bản xem trước của máy ảnh ở chế độ dọc được xoay
            ngang.
Hình 16. Thiết bị có thể gập chuyển đổi từ tỷ lệ khung hình dọc sang ngang nhưng cảm biến máy ảnh vẫn ở hướng dọc.

Trong hình 16, ứng dụng giả định nhầm rằng thiết bị đã xoay 90 độ ngược chiều kim đồng hồ; do đó, ứng dụng đã xoay bản xem trước theo cùng một góc.

Thiết bị có thể gập lại ở trạng thái mở ra, có bản xem trước của máy ảnh theo chiều dọc nhưng bị nén do tỷ lệ không chính xác.
Hình 17. Thiết bị gập chuyển từ tỷ lệ khung hình dọc sang ngang với bản xem trước của máy ảnh không được điều chỉnh theo tỷ lệ đúng cách.

Trong hình 17, ứng dụng không điều chỉnh tỷ lệ khung hình của vùng đệm hình ảnh để cho phép ứng dụng điều chỉnh tỷ lệ cho phù hợp với kích thước mới của phần tử giao diện người dùng xem trước của máy ảnh.

Các ứng dụng máy ảnh có hướng cố định thường gặp vấn đề trên thiết bị có thể gập lại và các thiết bị màn hình lớn khác như máy tính xách tay:

Bản xem trước của máy ảnh trên máy tính xách tay ở hướng dọc nhưng giao diện người dùng của ứng dụng lại ở hướng ngang.
Hình 18. Ứng dụng hướng dọc cố định trên máy tính xách tay.

Trong hình 18, giao diện người dùng của ứng dụng máy ảnh nằm ngang vì hướng của ứng dụng bị hạn chế chỉ ở chế độ dọc. Hình ảnh trong kính ngắm được định hướng chính xác so với cảm biến của camera.

Chế độ chân dung lồng ghép

Các ứng dụng máy ảnh không hỗ trợ chế độ nhiều cửa sổ (resizeableActivity="false") và hạn chế hướng (screenOrientation="portrait" hoặc screenOrientation="landscape") có thể được đặt ở chế độ chân dung lồng ghép trên các thiết bị màn hình lớn để định hướng đúng bản xem trước của máy ảnh.

Chế độ lồng ghép dọc sẽ lồng ghép (lồng ghép) các ứng dụng chỉ hiển thị theo chiều dọc theo hướng dọc, ngay cả khi tỷ lệ khung hình của màn hình là ngang. Ứng dụng chỉ hiển thị theo hướng ngang có dạng hòm thư theo hướng ngang mặc dù tỷ lệ khung hình hiển thị là dọc. Hình ảnh của máy ảnh được xoay để căn chỉnh với giao diện người dùng của ứng dụng, được cắt để khớp với tỷ lệ khung hình của bản xem trước máy ảnh, sau đó được điều chỉnh theo tỷ lệ để lấp đầy bản xem trước.

Chế độ chân dung lồng ghép được kích hoạt khi tỷ lệ khung hình của cảm biến hình ảnh máy ảnh và tỷ lệ khung hình của hoạt động chính trong ứng dụng không khớp nhau.

Bản xem trước của máy ảnh và giao diện người dùng của ứng dụng ở hướng dọc thích hợp trên máy tính xách tay.
            Hình ảnh xem trước rộng được điều chỉnh theo tỷ lệ và cắt cho vừa với hướng dọc.
Hình 19. Ứng dụng hướng dọc cố định ở chế độ dọc lồng ghép trên máy tính xách tay.

Trong hình 19, ứng dụng máy ảnh chỉ hỗ trợ chế độ dọc đã được xoay để hiển thị giao diện người dùng theo chiều dọc trên màn hình máy tính xách tay. Ứng dụng được tạo hiệu ứng hòm thư do sự khác biệt về tỷ lệ khung hình giữa ứng dụng dọc và màn hình ngang. Hình ảnh xem trước của máy ảnh đã được xoay để bù cho việc xoay giao diện người dùng của ứng dụng (do chế độ chân dung lồng ghép) và hình ảnh đã được cắt và điều chỉnh theo tỷ lệ để vừa với hướng dọc, làm giảm trường nhìn.

Xoay, cắt, điều chỉnh tỷ lệ

Chế độ chân dung lồng được gọi cho một ứng dụng máy ảnh chỉ hiển thị theo hướng dọc trên màn hình có tỷ lệ khung hình ngang:

Bản xem trước của máy ảnh trên máy tính xách tay ở hướng dọc nhưng giao diện người dùng của ứng dụng lại ở hướng ngang.
Hình 20. Ứng dụng hướng dọc cố định trên máy tính xách tay.

Ứng dụng có dạng hòm thư theo hướng dọc:

Ứng dụng được xoay theo hướng dọc và tạo hiệu ứng hòm thư. Hình ảnh nằm ngang, phần trên cùng nằm bên phải.
Hình 21. Ứng dụng chỉ hiển thị theo hướng dọc được xoay và có dạng hòm thư trên màn hình ngang, trước khi xoay hình ảnh cảm biến.

Hình ảnh camera được xoay 90 độ để điều chỉnh theo hướng mới của ứng dụng:

Hình ảnh cảm biến được xoay 90 độ để đặt thẳng đứng.
Hình 22. Hình ảnh camera được xoay 90 độ để căn chỉnh với giao diện người dùng của ứng dụng đã được định hướng lại.

Hình ảnh được cắt theo tỷ lệ khung hình của bản xem trước máy ảnh, sau đó được điều chỉnh theo tỷ lệ để lấp đầy bản xem trước (trường nhìn bị giảm):

Hình ảnh camera được cắt và điều chỉnh theo tỷ lệ để lấp đầy bản xem trước của camera.
Hình 23. Hình ảnh của máy ảnh được cắt và điều chỉnh theo tỷ lệ để lấp đầy bản xem trước của máy ảnh dọc.

Trên thiết bị có thể gập lại, hướng của cảm biến máy ảnh có thể là hướng dọc trong khi tỷ lệ khung hình của màn hình là hướng ngang:

Bản xem trước của máy ảnh và giao diện người dùng của ứng dụng bị xoay ngang trên màn hình rộng, mở ra.
Hình 24. Thiết bị mở ra có ứng dụng máy ảnh chỉ hỗ trợ hướng dọc và tỷ lệ khung hình của cảm biến máy ảnh và màn hình khác nhau.

Vì bản xem trước của máy ảnh được xoay để điều chỉnh theo hướng cảm biến, nên hình ảnh được định hướng đúng cách trong kính ngắm, nhưng ứng dụng chỉ hiển thị theo hướng dọc lại nằm ngang.

Chế độ chân dung lồng ghép chỉ cần hiển thị ứng dụng ở dạng hòm thư theo hướng dọc để định hướng đúng cách cho ứng dụng và bản xem trước của máy ảnh:

Ứng dụng có hiệu ứng hòm thư ở hướng dọc với bản xem trước của máy ảnh
            theo chiều dọc trên thiết bị có thể gập lại.
Hình 25. Ứng dụng chỉ hiển thị theo hướng dọc, có dạng hòm thư ở chế độ lồng ghép dọc trên một thiết bị có thể gập lại đang mở ra.

API

Kể từ Android 12 (API cấp 31), các ứng dụng cũng có thể kiểm soát rõ ràng chế độ chân dung lồng ghép bằng thuộc tính SCALER_ROTATE_AND_CROP của lớp CaptureRequest.

Giá trị mặc định là SCALER_ROTATE_AND_CROP_AUTO, cho phép hệ thống gọi chế độ chân dung lồng ghép. SCALER_ROTATE_AND_CROP_90 là hành vi của chế độ chân dung lồng ghép như mô tả ở trên.

Không phải thiết bị nào cũng hỗ trợ tất cả giá trị SCALER_ROTATE_AND_CROP. Để xem danh sách các giá trị được hỗ trợ, hãy tham khảo CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES.

CameraX

Thư viện Jetpack CameraX giúp bạn dễ dàng tạo một kính ngắm máy ảnh phù hợp với hướng cảm biến và chế độ xoay thiết bị.

Phần tử bố cục PreviewView tạo bản xem trước của máy ảnh, tự động điều chỉnh theo hướng cảm biến, chế độ xoay thiết bị và tỷ lệ. PreviewView duy trì tỷ lệ khung hình của hình ảnh camera bằng cách áp dụng loại tỷ lệ FILL_CENTER. Loại tỷ lệ này căn giữa hình ảnh nhưng có thể cắt hình ảnh để phù hợp với kích thước của PreviewView. Để tạo hiệu ứng hòm thư cho hình ảnh camera, hãy đặt loại tỷ lệ thành FIT_CENTER.

Để tìm hiểu kiến thức cơ bản về cách tạo bản xem trước của camera bằng PreviewView, hãy xem phần Triển khai bản xem trước.

Để xem cách triển khai mẫu hoàn chỉnh, hãy xem kho lưu trữ CameraXBasic trên GitHub.

CameraViewfinder

Tương tự như trường hợp sử dụng Preview, thư viện CameraViewfinder cung cấp một bộ công cụ để đơn giản hoá việc tạo bản xem trước của camera. Thư viện này không phụ thuộc vào CameraX Core, nên bạn có thể tích hợp liền mạch vào toàn bộ mã nguồn Camera2 hiện có.

Thay vì sử dụng trực tiếp Surface, bạn có thể dùng tiện ích CameraViewfinder để hiển thị nguồn cấp dữ liệu từ camera cho Camera2.

CameraViewfinder sử dụng nội bộ TextureView hoặc SurfaceView để hiển thị nguồn cấp dữ liệu từ camera và áp dụng các phép biến đổi cần thiết trên đó để hiển thị chính xác kính ngắm. Điều này bao gồm việc điều chỉnh tỷ lệ khung hình, tỷ lệ và chế độ xoay.

Để yêu cầu nền tảng từ đối tượng CameraViewfinder, bạn cần tạo một ViewfinderSurfaceRequest.

Yêu cầu này chứa các yêu cầu về độ phân giải của nền tảng và thông tin về thiết bị camera từ CameraCharacteristics.

Việc gọi requestSurfaceAsync() sẽ gửi yêu cầu đến nhà cung cấp nền tảng (TextureView hoặc SurfaceView) và nhận được ListenableFuture của Surface.

Việc gọi markSurfaceSafeToRelease() sẽ thông báo cho nhà cung cấp nền tảng rằng nền tảng đó không cần thiết và các tài nguyên có liên quan có thể được giải phóng.

fun startCamera() {
    val previewResolution = Size(width, height)
    val viewfinderSurfaceRequest =
        ViewfinderSurfaceRequest(previewResolution, characteristics)
    val surfaceListenableFuture =
        cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest)

    Futures.addCallback(surfaceListenableFuture, object : FutureCallback<Surface> {
        override fun onSuccess(surface: Surface) {
            /* create a CaptureSession using this surface as usual */
        }
        override fun onFailure(t: Throwable) { /* something went wrong */ }
    }, ContextCompat.getMainExecutor(context))
}

SurfaceView

SurfaceView là một phương pháp đơn giản để tạo bản xem trước của máy ảnh nếu bản xem trước không cần xử lý và không có ảnh động.

SurfaceView tự động xoay vùng đệm hình ảnh của cảm biến máy ảnh để khớp với hướng màn hình, tính đến cả hướng cảm biến và độ xoay thiết bị. Tuy nhiên, vùng đệm hình ảnh được điều chỉnh theo tỷ lệ để vừa với kích thước SurfaceView mà không cần xem xét tỷ lệ khung hình.

Bạn phải đảm bảo rằng tỷ lệ khung hình của vùng đệm hình ảnh khớp với tỷ lệ khung hình của SurfaceView. Bạn có thể thực hiện việc này bằng cách điều chỉnh tỷ lệ nội dung của SurfaceView trong phương thức onMeasure() của thành phần:

(Mã nguồn computeRelativeRotation() nằm trong phần Xoay tương đối bên dưới.)

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    val width = MeasureSpec.getSize(widthMeasureSpec)
    val height = MeasureSpec.getSize(heightMeasureSpec)

    val relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees)

    if (previewWidth > 0f && previewHeight > 0f) {
        /* Scale factor required to scale the preview to its original size on the x-axis. */
        val scaleX =
            if (relativeRotation % 180 == 0) {
                width.toFloat() / previewWidth
            } else {
                width.toFloat() / previewHeight
            }
        /* Scale factor required to scale the preview to its original size on the y-axis. */
        val scaleY =
            if (relativeRotation % 180 == 0) {
                height.toFloat() / previewHeight
            } else {
                height.toFloat() / previewWidth
            }

        /* Scale factor required to fit the preview to the SurfaceView size. */
        val finalScale = min(scaleX, scaleY)

        setScaleX(1 / scaleX * finalScale)
        setScaleY(1 / scaleY * finalScale)
    }
    setMeasuredDimension(width, height)
}

Để biết thêm thông tin chi tiết về cách triển khai SurfaceView dưới dạng bản xem trước của máy ảnh, hãy xem bài viết Hướng máy ảnh.

TextureView

TextureView có hiệu suất thấp hơn SurfaceView và cần nhiều thao tác hơn, nhưng TextureView cho phép bạn kiểm soát tối đa bản xem trước của máy ảnh.

TextureView xoay vùng đệm hình ảnh của cảm biến dựa trên hướng cảm biến nhưng không xử lý việc xoay thiết bị hoặc điều chỉnh tỷ lệ xem trước.

Bạn có thể mã hoá việc điều chỉnh tỷ lệ và xoay trong phép biến đổi Matrix. Để tìm hiểu cách điều chỉnh tỷ lệ và xoay TextureView một cách chính xác, hãy xem bài viết Hỗ trợ các nền tảng có thể đổi kích thước trong ứng dụng camera.

Xoay tương đối

Độ xoay tương đối của cảm biến máy ảnh là mức độ xoay cần thiết để căn chỉnh đầu ra của cảm biến máy ảnh theo hướng của thiết bị.

Các thành phần như SurfaceView và TextureView sử dụng chế độ xoay tương đối để xác định hệ số tỷ lệ x và y cho hình ảnh xem trước. Trường này cũng được dùng để chỉ định chế độ xoay của vùng đệm hình ảnh cảm biến.

Các lớp CameraCharacteristics và Surface cho phép tính toán chế độ xoay tương đối của cảm biến máy ảnh:

/**
 * Computes rotation required to transform the camera sensor output orientation to the
 * device's current orientation in degrees.
 *
 * @param characteristics The CameraCharacteristics to query for the sensor orientation.
 * @param surfaceRotationDegrees The current device orientation as a Surface constant.
 * @return Relative rotation of the camera sensor output.
 */
public fun computeRelativeRotation(
    characteristics: CameraCharacteristics,
    surfaceRotationDegrees: Int
): Int {
    val sensorOrientationDegrees =
        characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION) ?: 0

    // Reverse device orientation for back-facing cameras.
    val sign = if (characteristics.get(CameraCharacteristics.LENS_FACING) ==
        CameraCharacteristics.LENS_FACING_FRONT
    ) 1 else -1

    // Calculate desired orientation relative to camera orientation to make
    // the image upright relative to the device orientation.
    return (sensorOrientationDegrees - surfaceRotationDegrees * sign + 360) % 360
}

Chỉ số cửa sổ

Bạn không nên dùng kích thước màn hình để xác định kích thước của kính ngắm máy ảnh; ứng dụng máy ảnh có thể đang chạy trong một phần màn hình, ở chế độ nhiều cửa sổ trên thiết bị di động hoặc chế độ dạng thức tuỳ ý trên ChromeOS.

WindowManager#getCurrentWindowMetrics() (được thêm vào cấp độ API 30) trả về kích thước của cửa sổ ứng dụng thay vì kích thước của màn hình. Các phương thức WindowMetricsCalculator#computeCurrentWindowMetrics() và WindowInfoTracker#currentWindowMetrics() trong thư viện WindowManager của Jetpack cung cấp chức năng hỗ trợ tương tự nhưng có khả năng tương thích ngược với cấp độ API 14.

xoay 180 độ

Việc xoay thiết bị 180 độ (ví dụ: từ hướng tự nhiên sang hướng tự nhiên lộn ngược) không kích hoạt lệnh gọi lại onConfigurationChanged(). Do đó, bản xem trước của máy ảnh có thể bị lộn ngược.

Để phát hiện góc xoay 180 độ, hãy triển khai DisplayListener và kiểm tra góc xoay của thiết bị bằng lệnh gọi đến Display#getRotation() trong lệnh gọi lại onDisplayChanged().

Tài nguyên độc quyền

Trước Android 10, chỉ hoạt động hiển thị trên cùng trong môi trường nhiều cửa sổ mới ở trạng thái RESUMED. Điều này gây nhầm lẫn cho người dùng vì hệ thống không cho biết hoạt động nào đã được tiếp tục.

Android 10 (cấp độ API 29) ra mắt tính năng tiếp tục nhiều lần, trong đó tất cả hoạt động hiển thị đều ở trạng thái RESUMED. Các hoạt động hiển thị vẫn có thể chuyển sang trạng thái PAUSED nếu, ví dụ: một hoạt động minh bạch nằm trên hoạt động đó hoặc khi không thể lấy hoạt động đó làm tâm điểm, chẳng hạn như ở chế độ hình trong hình (xem phần Hỗ trợ chế độ hình trong hình).

Ứng dụng sử dụng máy ảnh, micrô hoặc bất kỳ tài nguyên độc quyền hay singleton nào trên cấp độ API 29 trở lên đều phải hỗ trợ chế độ tiếp tục nhiều lần. Ví dụ: nếu ba hoạt động được tiếp tục muốn sử dụng máy ảnh, thì chỉ một hoạt động có thể truy cập vào tài nguyên độc quyền này. Mỗi hoạt động phải triển khai một lệnh gọi lại onDisconnected() để luôn nhận biết được quyền truy cập ưu tiên vào máy ảnh của một hoạt động có mức độ ưu tiên cao hơn.

Để biết thêm thông tin, hãy xem phần Tiếp tục nhiều hoạt động.

Tài nguyên khác