Lưu ý: Trang này đề cập đến gói Camera2. 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 từ Camera2, bạn nên sử dụng CameraX. Cả CameraX và Camera2 đều hỗ trợ Android 5.0 (API cấp 21) trở lên.
Bản xem trước của máy ảnh và máy ảnh không phải lúc nào cũng theo cùng một hướng trên Android thiết bị.
Camera nằm ở một vị trí cố định trên một thiết bị, bất kể thiết bị đó là điện thoại, máy tính bảng hoặc máy tính. Khi hướng của thiết bị thay đổi, hướng máy ảnh thay đổi.
Do đó, ứ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 của máy ảnh. Khi một điện thoại theo hướng dọc, bản xem trước của máy ảnh được giả định là cao hơn chiều rộng. Khi điện thoại (và máy ảnh) được xoay ngang, bản xem trước của máy ảnh dự kiến sẽ rộng 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ư có thể gập lại thiết bị và các chế độ hiển thị chẳng hạn như nhiều cửa sổ và nhiều màn hình. Thiết bị có thể gập lại thay đổi kích thước màn hình và tỷ lệ khung hình mà không cần thay đổi hướng. Chế độ nhiều cửa sổ ràng buộc các ứng dụng máy ảnh trong một phần của 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 của thiết bị. Chế độ nhiều màn hình cho phép sử dụng màn hình phụ mà có thể không có cùng hướng với màn hình chính.
Hướng máy ảnh
Chiến lược phát hành đĩa đơn Định nghĩa về khả năng tương thích với Android chỉ định rằng cảm biến hình ảnh của máy ảnh "PHẢI được định hướng để kích thước 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 trong hướng ngang. Điều này áp dụng bất kể chế độ cài đặt tự nhiên của thiết bị hướng; áp dụng cho các thiết bị chính theo chiều ngang cũng như thiết bị chính dọc".
Tính năng sắp xếp máy ảnh theo màn hình giúp tối đa hoá khu vực hiển thị của máy ảnh trong ứng dụng máy ảnh. Ngoài ra, cảm biến hình ảnh thường xuất dữ liệu theo tỷ lệ khung hình ngang, 4:3 là phổ biến nhất.
![Cảm biến của điện thoại và máy ảnh cả theo hướng dọc.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/camera_preview_portrait_front_facing.png?authuser=9&hl=vi)
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 mặt trước (máy ảnh hướng theo cùng hướng với màn hình) 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,
camera2 bao gồm một
SENSOR_ORIENTATION
hằng số. Đối với hầu hết điện thoại và máy tính bảng, thiết bị báo cáo hướng cảm biến
270 độ đối với máy ảnh mặt trước và 90 độ (góc nhìn từ
mặt sau của thiết bị) cho máy ảnh mặt sau, được căn chỉnh cạnh dài của
với cạnh dài của thiết bị. Camera của máy tính xách tay thường báo cáo
hướng cảm biến 0 hoặc 180 độ.
Do các cảm biến hình ảnh của camera xuất dữ liệu (vùng đệm hình ảnh) trong
hướng tự nhiên của cảm biến (ngang), vùng đệm hình ảnh phải được xoay
số độ mà SENSOR_ORIENTATION
chỉ định cho bản xem trước của máy ảnh
hiển thị thẳng đứng theo hướng tự nhiên của thiết bị. Đối với máy ảnh mặt trước,
xoay ngược chiều kim đồng hồ; đối với máy ảnh mặt sau, theo chiều kim đồng hồ.
Ví dụ: đối với máy ảnh mặt trước trong hình 1, vùng đệm hình ảnh do cảm biến của camera tạo ra trông giống như sau:
![Cảm biến của máy ảnh được xoay theo hướng ngang kèm hình ảnh
lệch sang một bên, trên cùng bên trái.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/camera_sensor_portrait_rotated_90.png?authuser=9&hl=vi)
Hình ảnh phải được xoay 270 độ ngược chiều kim đồng hồ để hình ảnh xem trước hướng khớp với hướng của thiết bị:
![Cảm biến của máy ảnh theo hướng dọc với hình ảnh thẳng đứng.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/camera_sensor_portrait_without_coordinates.png?authuser=9&hl=vi)
Máy ảnh mặt sau sẽ tạo ra vùng đệm hình ảnh có cùng hướng
như vùng đệm ở trên, nhưng SENSOR_ORIENTATION
là 90 độ. Do đó,
vùng đệm xoay 90 độ theo chiều kim đồng hồ.
Xoay thiết bị
Độ xoay thiết bị là số độ xoay thiết bị so với vị trí tự nhiên hướng. Ví dụ: điện thoại theo hướng ngang có một thiết bị xoay 90 hoặc 270 độ, tuỳ thuộc vào hướng quay.
Vùng đệm hình ảnh của cảm biến của máy ảnh phải được xoay cùng một số độ với xoay thiết bị (ngoài số độ hướng cảm biến) cho bản xem trước của máy ảnh hiển thị theo chiều dọc.
Tính toán hướng
Hướng thích hợp của bản xem trước của máy ảnh sẽ xem xét cảm biến hướng và hướng xoay thiết bị.
Độ xoay tổng thể của vùng đệm hình ảnh cảm biến có thể được tính toán bằng cách sử dụng công thức sau:
rotation = (sensorOrientationDegrees - deviceOrientationDegrees * sign + 360) % 360
trong đó sign
là 1
đối với máy ảnh mặt trước, -1
đối với máy ảnh mặt sau.
Đối với máy ảnh mặt 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 mặt sau, cảm biến vùng đệm hình ảnh được xoay theo chiều kim đồng hồ.
Biểu thức deviceOrientationDegrees * sign + 360
chuyển đổi việc xoay thiết bị
từ ngược chiều kim đồng hồ sang chiều kim đồng hồ đối với máy ảnh mặt sau (ví dụ:
chuyển đổi 270 độ ngược chiều kim đồng hồ thành 90 độ theo chiều kim đồng hồ). Mô-đun
thao tác sẽ chia tỷ lệ kết quả xuống dưới 360 độ (ví dụ: chia tỷ lệ 540
độ xoay thành 180).
Các API khác nhau báo cáo việc xoay thiết bị theo cách khác nhau:
Display#getRotation()
cung cấp hướng xoay ngược chiều kim đồng hồ của thiết bị (từ điểm của người dùng lượt xem). Giá trị này cũng tương tự như công thức trên.OrientationEventListener#onOrientationChanged()
trả về độ xoay theo chiều kim đồng hồ của thiết bị (từ góc nhìn của người dùng). Phủ định giá trị đó để sử dụng trong công thức trên.
Máy ảnh mặt trước
![Bản xem trước của máy ảnh và cảm biến cả theo hướng ngang, cảm biến
ở phía bên phải.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/camera_preview_landscape_counterclockwise_front_facing.png?authuser=9&hl=vi)
Dưới đây là vùng đệm hình ảnh do cảm biến của máy ảnh tạo ra trong hình 2:
![Cảm biến của máy ảnh theo hướng ngang với hình ảnh thẳng đứng.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/camera_sensor_landscape.png?authuser=9&hl=vi)
Vùng đệm phải xoay 270 độ ngược chiều kim đồng hồ để điều chỉnh cho cảm biến hướng (xem Hướng máy ảnh ở trên):
![Cảm biến của máy ảnh được xoay theo hướng dọc với hình ảnh lệch sang một bên,
trên cùng bên phải.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/camera_sensor_landscape_rotated_270.png?authuser=9&hl=vi)
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 của máy ảnh trong hình 2:
![Cảm biến của máy ảnh được xoay theo hướng ngang kèm hình ảnh
thẳng đứng.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/camera_sensor_landscape_without_coordinates.png?authuser=9&hl=vi)
Sau đây là camera đã xoay sang phải theo hướng ngang:
![Bản xem trước của máy ảnh và cảm biến cả theo hướng ngang, nhưng
cảm biến bị lộn ngược.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/camera_preview_landscape_clockwise_front_facing.png?authuser=9&hl=vi)
Dưới đây là vùng đệm hình ảnh:
![Cảm biến của máy ảnh được xoay theo hướng ngang với hình ảnh lộn ngược
xuống.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/camera_sensor_landscape_clockwise.png?authuser=9&hl=vi)
Vùng đệm phải được xoay 270 độ ngược chiều kim đồng hồ để điều chỉnh cho cảm biến hướng:
![Cảm biến của máy ảnh được xếp hạng theo hướng dọc với hình ảnh lệch sang một bên,
trên cùng bên trái.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/camera_sensor_landscape_clockwise_rotated_270.png?authuser=9&hl=vi)
Sau đó, vùng đệm được xoay 270 độ ngược chiều kim đồng hồ để tính đến xoay thiết bị:
![Cảm biến của máy ảnh được xoay theo hướng ngang kèm hình ảnh
thẳng đứng.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/camera_sensor_landscape_without_coordinates.png?authuser=9&hl=vi)
Camera mặt sau
Máy ảnh mặt sau thường có hướng cảm biến 90 độ (như xem 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 được xoay theo chiều kim đồng hồ theo số góc xoay cảm biến (thay vì ngược chiều kim đồng hồ như máy ảnh mặt trước), sau đó chọn hình ảnh vùng đệm được xoay ngược chiều kim đồng hồ theo số vòng xoay của thiết bị.
![Bản xem trước của máy ảnh và cảm biến cả theo hướng ngang, nhưng
cảm biến bị lộn ngược.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/camera_preview_landscape_clockwise_back_facing.png?authuser=9&hl=vi)
Dưới đây là vùng đệm hình ảnh qua cảm biến của máy ảnh trong hình 4:
![Cảm biến của máy ảnh được xoay theo hướng ngang với hình ảnh lộn ngược
xuống.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/camera_sensor_landscape_clockwise.png?authuser=9&hl=vi)
Vùng đệm phải xoay 90 độ theo chiều kim đồng hồ để điều chỉnh cho cảm biến hướng:
![Cảm biến của máy ảnh được xếp hạng theo hướng dọc với hình ảnh lệch sang một bên,
trên cùng bên trái.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/camera_sensor_landscape_clockwise_rotated_270.png?authuser=9&hl=vi)
Sau đó, vùng đệm xoay 270 độ ngược chiều kim đồng hồ để phù hợp với thiết bị xoay:
![Cảm biến của máy ảnh được xoay theo hướng ngang kèm hình ảnh
thẳng đứng.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/camera_sensor_landscape_without_coordinates.png?authuser=9&hl=vi)
Tỷ lệ khung hình
Tỷ lệ khung hình của màn hình thay đổi khi hướng thiết bị thay đổi và cả khi thiết bị có thể gập lại và mở ra khi cửa sổ được đổi kích thước ở chế độ nhiều cửa sổ môi trường xung quanh và khi ứng dụng mở trên màn hình phụ.
Vùng đệm hình ảnh cảm biến của máy ảnh phải được định hướng và điều chỉnh theo tỷ lệ cho phù hợp với hướng và tỷ lệ cỡ ảnh của phần tử trên giao diện người dùng kính ngắm dưới dạng giao diện người dùng tự động thay đổi hướng – có hoặc không có thiết bị thay đổi hướng.
Trên các kiểu dáng mới hoặc trong môi trường nhiều cửa sổ hay nhiều màn hình, nếu ứng dụng 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) bản xem trước của bạn có thể không được định hướng đúng, điều chỉnh theo tỷ lệ không chính xác hoặc cả hai.
![Thiết bị có thể gập lại không gập lại đang bật chế độ xem trước của máy ảnh theo hướng dọc
lệch sang một bên.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/foldable_with_rotation_problem.png?authuser=9&hl=vi)
Trong hình 5, ứng dụng giả định nhầm rằng thiết bị đã được xoay 90 độ độ ngược chiều kim đồng hồ; và do đó, ứng dụng đã xoay bản xem trước theo cùng mức độ.
![Thiết bị có thể gập lại khi mở với bản xem trước của máy ảnh ở dạng thẳng đứng nhưng bị đè nén
do chia tỷ lệ không chính xác.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/foldable_with_scaling_problem.png?authuser=9&hl=vi)
Trong hình 6, ứng dụng không điều chỉnh tỷ lệ khung hình của vùng đệm hình ảnh thành cho phép nó điều chỉnh tỷ lệ đúng cách cho vừa với kích thước mới của giao diện người dùng bản xem trước của máy ảnh .
Ứng dụng máy ảnh hướng cố định thường gặp sự cố trên thiết bị có thể gập lại và thiết bị có 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 đang ở chế độ thẳng đứng, nhưng giao diện người dùng của ứng dụng bị lệch sang một bên.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/laptop_camera_preview_fixed-orientation_app.png?authuser=9&hl=vi)
Trong hình 7, giao diện người dùng của ứng dụng máy ảnh bị lệch sang một bên do hướng của ứng dụng chỉ hiển thị ở chế độ dọc. Hình ảnh kính ngắm được định hướng chính xác so với cảm biến của máy ảnh.
Lồng ghép chế độ dọc
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 của các em
(screenOrientation="portrait"
)
hoặc screenOrientation="landscape"
)
có thể được đặt ở chế độ dọc lồng ghép trên các thiết bị có màn hình lớn để định hướng đúng cách
bản xem trước của camera.
Lồng ghép các ứng dụng chỉ hiển thị theo chiều dọc ở chế độ dọc ở chế độ dọc mặc dù tỷ lệ khung hình của màn hình là ngang. Các ứng dụng chỉ hiển thị theo hướng ngang được tạo hiệu ứng hòm thư theo hướng ngang mặc dù thì tỷ lệ khung hình của màn hình là dọc. Hình ảnh máy ảnh được xoay để căn chỉnh cho giao diện người dùng của ứng dụng, được cắt cho phù hợp với tỷ lệ khung hình của bản xem trước camera, và sau đó điều chỉnh tỷ lệ để lấp đầy bản xem trước.
Chế độ dọc lồng ghép được kích hoạt khi tỷ lệ khung hình của hình ảnh máy ảnh cảm biến và tỷ lệ khung hình của hoạt động chính của ứng dụng không khớp.
![Bản xem trước của máy ảnh và giao diện người dùng của ứng dụng theo hướng dọc thích hợp trên máy tính xách tay.
Hình ảnh xem trước trên màn hình rộng được điều chỉnh theo tỷ lệ và cắt cho vừa với chiều dọc
hướng.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/laptop_inset_portrait_mode.png?authuser=9&hl=vi)
Trong hình 8, ứng dụng máy ảnh chỉ hiển thị theo hướng dọc đã được xoay để hiển thị giao diện người dùng thẳng đứng trên màn hình máy tính xách tay. Ứng dụng ở dạ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. Camera hình ảnh xem trước đã được xoay để bù cho việc xoay giao diện người dùng của ứng dụng (do lồng ghép và hình ảnh đã được cắt và điều chỉnh theo tỷ lệ cho vừa với hướng dọc, giảm trường nhìn.
Xoay, cắt, điều chỉnh theo tỷ lệ
Chế độ chân dung lồng ghép được gọi cho ứng dụng máy ảnh chỉ hiển thị 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 đang ở chế độ thẳng đứng, nhưng giao diện người dùng của ứng dụng bị lệch sang một bên.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/laptop_inset_portrait_mode_fixed-orientation_app.png?authuser=9&hl=vi)
Ứng dụng được tạo hiệu ứng hòm thư theo hướng dọc:
![Ứng dụng được xoay sang hướng dọc và có hiệu ứng hòm thư. Hình ảnh là
sang một bên, trên cùng bên phải.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/laptop_inset_portrait_mode_rotate_ui.png?authuser=9&hl=vi)
Hình ảnh máy ảnh được xoay 90 độ để điều chỉnh hướng của ứng dụng:
![Hình ảnh cảm biến đã xoay 90 độ để đứng thẳng.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/laptop_inset_portrait_mode_rotate_sensor_image.png?authuser=9&hl=vi)
Hình ảnh được cắt theo tỷ lệ khung hình của bản xem trước của máy ảnh, sau đó điều chỉnh tỷ lệ lấp đầy bản xem trước (trường nhìn giảm):
![Hình ảnh máy ảnh đã được cắt được điều chỉnh theo tỷ lệ để lấp đầy bản xem trước của máy ảnh.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/laptop_inset_portrait_mode_crop_and_scale.png?authuser=9&hl=vi)
Trên các thiết bị có thể gập lại, hướng của cảm biến của máy ảnh có thể là hướng dọc trong khi tỷ lệ khung hình của màn hình là 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ị lệch sang một bên trên màn hình rộng và mở.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/unfolded_phone_camera_preview_fixed-orientation_app.png?authuser=9&hl=vi)
Vì bản xem trước của máy ảnh được xoay để điều chỉnh hướng cảm biến, hình ảnh được định hướng chính xác trong kính ngắm, nhưng ứng dụng chỉ hiển thị theo hướng dọc lệch sang một bên.
Lồng ghép chế độ dọc chỉ cần tạo hiệu ứng hòm thư cho ứng dụng theo hướng dọc để định hướng đúng cách bản xem trước ứng dụng và máy ảnh:
![Ứng dụng dạng hòm thư theo hướng dọc với bản xem trước của máy ảnh
thẳng đứng trên thiết bị có thể gập lại.](https://developer.android.google.cn/static/images/training/camera/camera2/camera-preview/unfolded_phone_inset_portrait_mode.png?authuser=9&hl=vi)
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 phần lồng ghép dọc
thông qua phương pháp
SCALER_ROTATE_AND_CROP
thuộc tính của CaptureRequest
.
Giá trị mặc định là
SCALER_ROTATE_AND_CROP_AUTO
!
cho phép hệ thống gọi chế độ dọc lồng ghép.
SCALER_ROTATE_AND_CROP_90
là hành vi của chế độ dọc có phần lồng ghép như mô tả ở trên.
Không phải thiết bị nào cũng hỗ trợ toàn bộ giá trị SCALER_ROTATE_AND_CROP
. Cách lấy danh sách
giá trị được hỗ trợ, tham chiếu
CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES
.
CameraX
Thư viện Jetpack CameraX giúp tạo ra kính ngắm máy ảnh phù hợp với hướng cảm biến và xoay thiết bị một nhiệm vụ đơn giản.
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,
xoay thiết bị và chuyển tỷ lệ. PreviewView
duy trì tỷ lệ khung hình của
hình ảnh máy ảnh bằng cách áp dụng
FILL_CENTER
loại tỷ lệ, căn giữa hình ảnh nhưng có thể cắt hình ảnh cho phù hợp với kích thước
của PreviewView
. Để hòm thư cho hình ảnh camera, hãy đặt loại tỷ lệ thành
FIT_CENTER
.
Để tìm hiểu thông tin cơ bản về cách tạo bản xem trước của máy ảnh bằng PreviewView
, hãy xem
Triển khai bản xem trước.
Để triển khai mẫu hoàn chỉnh, hãy xem
CameraXBasic
kho lưu trữ trên GitHub.
Kính ngắm camera
Tương tự như trường hợp sử dụng Xem trước, CameraViewfinder cung cấp một bộ công cụ giúp đơn giản hoá việc tạo bản xem trước của máy ảnh. Nó 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 cơ sở mã Camera2 hiện có.
Thay vì sử dụng
Surface
trực tiếp, bạn có thể sử dụng
CameraViewfinder
để hiển thị nguồn cấp dữ liệu máy ảnh cho Camera2.
CameraViewfinder
sử dụng nội bộ TextureView
hoặc SurfaceView
để hiển thị nguồn cấp dữ liệu máy ảnh và áp dụng các phép biến đổi cần thiết cho nguồn cấp dữ liệu máy ảnh
hiển thị chính xác kính ngắm.
Quá trình này bao gồm việc điều chỉnh tỷ lệ khung hình, tỷ lệ và xoay.
Để yêu cầu nền tảng từ đối tượng CameraViewfinder
, bạn cần phải
tạo một ViewfinderSurfaceRequest
.
Yêu cầu này chứa các yêu cầu về độ phân giải bề mặt và thiết bị máy ảnh
từ CameraCharacteristics
.
Đang gọi requestSurfaceAsync()
gửi yêu cầu đến trình cung cấp nền tảng, đó là TextureView
hoặc
SurfaceView
và nhận được ListenableFuture
Surface
.
Đang gọi markSurfaceSafeToRelease()
thông báo cho nhà cung cấp nền tảng rằng nền tảng là không cần thiết và có liên quan
có thể được phát hành.
Kotlin
fun startCamera(){ val previewResolution = Size(width, height) val viewfinderSurfaceRequest = ViewfinderSurfaceRequest(previewResolution, characteristics) val surfaceListenableFuture = cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest) Futures.addCallback(surfaceListenableFuture, object : FutureCallbackS<urface >{ override fun onSuccess(surface: Surface) { /* create a CaptureSession using this surface as usual */ } override fun onFailure(t: Throwable) { /* something went wrong */} }, ContextCompat.getMainExecutor(context)) }
Java
void startCamera(){ Size previewResolution = new Size(width, height); ViewfinderSurfaceRequest viewfinderSurfaceRequest = new ViewfinderSurfaceRequest(previewResolution, characteristics); ListenableFutureS<urface >surfaceListenableFuture = cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest); Futures.addCallback(surfaceListenableFuture, new FutureCallbackS<urface(>) { @Override public void onSuccess(Surface result) { /* create a CaptureSession using this surface as usual */ } @Override public void onFailure(Throwable t) { /* 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 này không
yêu cầu xử lý và không được tạo ảnh động.
SurfaceView
tự động xoay vùng đệm hình ảnh cảm biến của máy ảnh cho phù hợp
hướng màn hình, có tính đến cả hướng cảm biến và thiết bị
xoay. Tuy nhiên, vùng đệm hình ảnh được điều chỉnh theo tỷ lệ cho vừa với SurfaceView
mà không cần xem xét đến 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 khung hình
tỷ lệ SurfaceView
mà bạn có thể đạt được bằng cách chia tỷ lệ nội dung
của SurfaceView
trong phần tử của thành phần
onMeasure()
phương thức:
(Mã nguồn computeRelativeRotation()
nằm trong
Xoay vòng tương đối bên dưới.)
Kotlin
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) }
Java
@Override void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); int relativeRotation = computeRelativeRotation(characteristics, surfaceRotationDegrees); if (previewWidth > 0f && previewHeight > 0f) { /* Scale factor required to scale the preview to its original size on the x-axis. */ float scaleX = (relativeRotation % 180 == 0) ? (float) width / previewWidth : (float) width / previewHeight; /* Scale factor required to scale the preview to its original size on the y-axis. */ float scaleY = (relativeRotation % 180 == 0) ? (float) height / previewHeight : (float) height / previewWidth; /* Scale factor required to fit the preview to the SurfaceView size. */ float finalScale = Math.min(scaleX, scaleY); setScaleX(1 / scaleX * finalScale); setScaleY(1 / scaleY * finalScale); } setMeasuredDimension(width, height); }
Để biết thêm thông tin về cách triển khai SurfaceView
làm bản xem trước của máy ảnh, hãy xem
Hướng máy ảnh.
Chế độ xem kết cấu
TextureView
có hiệu suất kém hơn
SurfaceView
— và nhiều việc khác, nhưng TextureView
sẽ mang lại cho bạn tối đa
quyền kiểm soát bản xem trước của camera.
TextureView
xoay vùng đệm hình ảnh 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.
Việc điều chỉnh tỷ lệ và xoay có thể được mã hoá theo
Biến đổi ma trận. Để 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
Hỗ trợ các nền tảng có thể đổi kích thước trong ứng dụng máy ảnh
Xoay tương đối
Độ xoay tương đối của cảm biến máy ảnh là số vòng xoay cần thiết để căn chỉnh đầu ra cảm biến của máy ảnh theo hướng của thiết bị.
Chế độ xoay tương đối được các thành phần như SurfaceView
và TextureView
sử dụng
để xác định hệ số tỷ lệ x và y cho hình ảnh xem trước. Tên này cũng được dùng để
chỉ định chế độ xoay của vùng đệm hình ảnh cảm biến.
Chiến lược phát hành đĩa đơn
CameraCharacteristics
và
Các lớp Surface
cho phép tính toán
độ xoay tương đối của cảm biến máy ảnh:
Kotlin
/** * 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)!! // 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 }
Java
/** * 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 int computeRelativeRotation( CameraCharacteristics characteristics, int surfaceRotationDegrees ){ Integer sensorOrientationDegrees = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); // Reverse device orientation for back-facing cameras. int sign = characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT ? 1 : -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ổ
Không nên sử dụng kích thước màn hình để xác định kích thước của máy ảnh kính ngắm; ứng dụng máy ảnh có thể đang chạy ở một phần của màn hình ở chế độ nhiều cửa sổ trên thiết bị di động hoặc ở chế độ rời trên ChromeOS.
WindowManager#getCurrentWindowMetrics()
(được thêm vào API cấp 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 thư viện Jetpack WindowManager
WindowMetricsCalculator#computeCurrentWindowMetrics()
và
WindowInfoTracker#currentWindowMetrics()
cung cấp khả năng hỗ trợ tương tự có khả năng tương thích ngược với API cấp 14.
xoay 180 độ
Xoay 180 độ của thiết bị (ví dụ: từ hướng tự nhiên sang
hướng tự nhiên lộn ngược) sẽ không kích hoạt
onConfigurationChanged()
. Do đó, bản xem trước của máy ảnh có thể bị lộn ngược.
Để phát hiện chế độ xoay 180 độ, hãy triển khai một
DisplayListener
và kiểm tra chế độ xoay của thiết bị bằng lệnh gọi đến
Display#getRotation()
trong
onDisplayChanged()
.
Tài nguyên độc quyền
Trước Android 10, chỉ hoạt động ở trên cùng mới được hiển thị trong chế độ nhiều cửa sổ
môi trường đã ở 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 cung cấp chỉ báo nào về hoạt động nào đã được tiếp tục.
Android 10 (API cấp 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ị
đang ở trạng thái RESUMED
. Các hoạt động hiển thị vẫn có thể truy cập vào PAUSED
trạng thái nếu, ví dụ: một hoạt động rõ ràng nằm ở trên hoạt động hoặc
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
Hỗ trợ chế độ hình trong hình).
Một ứng dụng sử dụng máy ảnh, micrô hoặc bất kỳ
tài nguyên singleton trên API cấp 29 trở lên phải hỗ trợ tính năng tiếp tục nhiều lần. Cho
Ví dụ: nếu ba hoạt động đã tiếp tục muốn sử dụng camera, 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
onDisconnected()
gọi lại để nhận biết quyền truy cập trước vào máy ảnh theo mức độ ưu tiên cao hơn
của bạn.
Để biết thêm thông tin, hãy xem Tiếp tục nhiều lần.
Tài nguyên khác
- Để xem mẫu Camera2, hãy xem ứng dụng Camera2Basic trên GitHub.
- Để tìm hiểu về trường hợp sử dụng bản xem trước của CameraX, hãy xem bài viết CameraX Triển khai bản xem trước.
- Để triển khai mẫu bản xem trước của máy ảnh CameraX, hãy xem CameraXBasic kho lưu trữ trên GitHub.
- Để biết thông tin về bản xem trước của máy ảnh trên ChromeOS, hãy xem Hướng máy ảnh.
- Để biết thông tin về cách phát triển cho thiết bị có thể gập lại, hãy xem Tìm hiểu về thiết bị có thể gập lại.