Khung Android hỗ trợ nhiều máy ảnh và tính năng máy ảnh có trên cho phép bạn chụp ảnh và quay video trong ứng dụng của mình. Tài liệu này thảo luận về một nhanh chóng, đơn giản để chụp ảnh và quay video, đồng thời phác thảo một phương pháp nâng cao để tạo cho người dùng của mình.
Lưu ý:
Trang này mô tả
Camera
lớp này đã không được dùng nữa. Bạn nên sử dụng
Thư viện Jetpack CameraX hoặc (trong một số trường hợp sử dụng cụ thể),
camera2
,
. Cả CameraX và Camera2 đều hoạt động trên Android 5.0 (API cấp 21) và
cao hơn.
Hãy tham khảo các tài nguyên liên quan sau:
Những yếu tố nên cân nhắc
Trước khi bật ứng dụng của bạn để sử dụng máy ảnh trên thiết bị Android, bạn nên cân nhắc một số về cách ứng dụng của bạn dự định sử dụng tính năng phần cứng này.
- Yêu cầu về máy ảnh – Việc sử dụng máy ảnh có quá quan trọng đối với bạn không ứng dụng mà bạn không muốn ứng dụng của mình được cài đặt trên thiết bị không có camera? Nếu có, bạn nên khai báo yêu cầu về camera trong tệp kê khai.
- Hình ảnh nhanh hoặc Camera tuỳ chỉnh - Ứng dụng của bạn sẽ sử dụng camera? Bạn chỉ muốn chụp nhanh một bức ảnh hoặc đoạn video ngắn hay đơn đăng ký của bạn đưa ra cách mới để sử dụng camera? Để chụp nhanh hoặc tạo đoạn video ngắn, hãy cân nhắc Sử dụng các ứng dụng máy ảnh hiện có. Để phát triển một tính năng camera tuỳ chỉnh, hãy xem phần Xây dựng ứng dụng máy ảnh.
- Yêu cầu đối với dịch vụ trên nền trước – Khi nào ứng dụng của bạn tương tác với camera? Trên Android 9 (API cấp 28) trở lên, các ứng dụng chạy trong nền không thể truy cập máy ảnh. Do đó, bạn nên sử dụng camera khi ứng dụng của bạn chạy ở nền trước hoặc là một phần của dịch vụ trên nền trước.
- Bộ nhớ – Hình ảnh hoặc video mà ứng dụng của bạn tạo ra nhằm mục đích chỉ hiển thị với ứng dụng của bạn hoặc được chia sẻ để các ứng dụng khác như Thư viện hoặc các ứng dụng khác và các ứng dụng mạng xã hội có thể sử dụng không? Bạn có muốn hình ảnh và video có sẵn ngay cả khi ứng dụng của bạn đã bị gỡ cài đặt chưa? Hãy xem phần Lưu tệp nội dung nghe nhìn để xem cách triển khai các tuỳ chọn này.
Thông tin cơ bản
Khung Android hỗ trợ chụp ảnh và quay video thông qua
API android.hardware.camera2
hoặc camera Intent
. Sau đây là các báo cáo liên quan
lớp:
android.hardware.camera2
- Gói này là API chính để điều khiển các máy ảnh của thiết bị. Dữ liệu này có thể được dùng để lấy ảnh hoặc video khi bạn tạo ứng dụng máy ảnh.
Camera
- Lớp này là API cũ không dùng nữa để điều khiển máy ảnh của thiết bị.
SurfaceView
- Lớp này được dùng để hiển thị bản xem trước của camera trực tiếp cho người dùng.
MediaRecorder
- Lớp học này dùng để quay video từ máy ảnh.
Intent
- Bạn có thể sử dụng loại thao tác theo ý định
MediaStore.ACTION_IMAGE_CAPTURE
hoặcMediaStore.ACTION_VIDEO_CAPTURE
để chụp ảnh hoặc quay video mà không cần trực tiếp bằng cách sử dụng đối tượngCamera
.
Nội dung khai báo trong tệp kê khai
Trước khi bắt đầu phát triển ứng dụng bằng Camera API, bạn cần đảm bảo tệp kê khai của bạn có các nội dung khai báo thích hợp để cho phép sử dụng phần cứng máy ảnh cũng như các tính năng liên quan.
- Quyền máy ảnh – Ứng dụng của bạn phải yêu cầu quyền để sử dụng một thiết bị
máy ảnh.
<uses-permission android:name="android.permission.CAMERA" />
Lưu ý: Nếu bạn đang sử dụng máy ảnh bằng cách gọi một ứng dụng camera hiện có, ứng dụng của bạn không cần yêu cầu quyền này.
- Tính năng của máy ảnh – Ứng dụng của bạn cũng phải khai báo việc sử dụng các tính năng của máy ảnh,
ví dụ:
<uses-feature android:name="android.hardware.camera" />
Để biết danh sách các tính năng của máy ảnh, hãy xem tệp kê khai Tính năng Tệp đối chiếu.
Việc thêm các tính năng máy ảnh vào tệp kê khai sẽ khiến Google Play ngăn ứng dụng của bạn được cài đặt trên các thiết bị không có máy ảnh hoặc không hỗ trợ các tính năng máy ảnh mà bạn chỉ định. Để biết thêm thông tin về cách sử dụng cơ chế lọc dựa trên tính năng với Google Play, hãy xem phần Google Play và cơ chế lọc dựa trên tính năng.
Nếu ứng dụng của bạn có thể sử dụng tính năng của máy ảnh hoặc máy ảnh để hoạt động bình thường, nhưng không yêu cầu mã, bạn nên chỉ định thông tin này trong tệp kê khai bằng cách bao gồm thuộc tính
android:required
rồi đặt thuộc tính này thànhfalse
:<uses-feature android:name="android.hardware.camera" android:required="false" />
- Quyền truy cập vào bộ nhớ – Ứng dụng của bạn có thể lưu hình ảnh hoặc video vào
bộ nhớ ngoài của thiết bị (Thẻ SD) nếu thiết bị đó nhắm đến Android 10 (API cấp 29) hoặc
thấp hơn và chỉ định những nội dung sau trong tệp kê khai.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- Quyền ghi âm – Để ghi âm bằng tính năng quay video,
phải yêu cầu quyền ghi âm.
<uses-permission android:name="android.permission.RECORD_AUDIO" />
-
Quyền truy cập thông tin vị trí – Nếu ứng dụng của bạn gắn thẻ hình ảnh có thông tin vị trí GPS, bạn phải yêu cầu
ACCESS_FINE_LOCATION
quyền. Xin lưu ý rằng nếu ứng dụng của bạn nhắm đến Android 5.0 (API cấp 21) hoặc cao hơn, bạn cũng cần khai báo rằng ứng dụng sử dụng GPS của thiết bị:<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> ... <!-- Needed only if your app targets Android 5.0 (API level 21) or higher. --> <uses-feature android:name="android.hardware.location.gps" />
Để biết thêm thông tin về cách nhận thông tin vị trí của người dùng, hãy xem Chiến lược vị trí.
Sử dụng các ứng dụng máy ảnh hiện có
Một cách nhanh chóng để chụp ảnh hoặc quay video trong ứng dụng của bạn mà không cần nhiều mã bổ sung
là sử dụng Intent
để gọi một ứng dụng máy ảnh hiện có trên Android.
Thông tin chi tiết được mô tả trong các bài học đào tạo
Chụp ảnh đơn giản và
Quay video một cách dễ dàng.
Tạo ứng dụng máy ảnh
Một số nhà phát triển có thể yêu cầu giao diện người dùng camera được tuỳ chỉnh theo giao diện của họ hoặc cung cấp các tính năng đặc biệt. Viết mã chụp ảnh của riêng bạn có thể mang lại trải nghiệm hấp dẫn hơn cho người dùng.
Lưu ý: Hướng dẫn sau đây dành cho Camera
cũ và không còn dùng nữa
API. Đối với các ứng dụng máy ảnh mới hoặc nâng cao, API android.hardware.camera2
mới hơn
nên dùng.
Sau đây là các bước chung để tạo giao diện máy ảnh tuỳ chỉnh cho ứng dụng:
- Phát hiện và truy cập camera – Tạo mã để kiểm tra sự tồn tại của camera và yêu cầu quyền truy cập.
- Tạo Lớp xem trước – Tạo lớp xem trước cho máy ảnh giúp mở rộng
SurfaceView
và triển khai giao diệnSurfaceHolder
. Chiến dịch này xem trước hình ảnh trực tiếp từ máy ảnh. - Tạo bố cục bản xem trước – Sau khi có lớp xem trước của máy ảnh, hãy tạo một bố cục chế độ xem kết hợp bản xem trước và các chế độ điều khiển giao diện người dùng mà bạn muốn.
- Thiết lập trình nghe cho Capture – Kết nối trình nghe cho giao diện của bạn các nút điều khiển để bắt đầu chụp ảnh hoặc quay video nhằm phản hồi thao tác của người dùng, chẳng hạn như nhấn .
- Capture and Save Files (Chụp và lưu tệp) – Thiết lập mã để chụp ảnh hoặc video và lưu đầu ra.
- Phát hành Máy ảnh – Sau khi sử dụng máy ảnh, ứng dụng của bạn phải phát hành chính xác để các ứng dụng khác sử dụng.
Phần cứng máy ảnh là một tài nguyên dùng chung phải được quản lý cẩn thận để ứng dụng của bạn không xung đột với các ứng dụng khác cũng có thể muốn sử dụng nó. Các phần sau đây sẽ thảo luận cách phát hiện phần cứng của máy ảnh, cách yêu cầu quyền truy cập vào máy ảnh, cách chụp ảnh hoặc quay video và cách giải phóng camera khi sử dụng xong ứng dụng.
Thận trọng: Hãy nhớ phát hành Camera
bằng cách gọi Camera.release()
khi
đã sử dụng xong! Nếu ứng dụng của bạn không thả camera đúng cách, tất cả
những lần thử truy cập máy ảnh tiếp theo, bao gồm cả những lần truy cập bằng ứng dụng của chính bạn, sẽ không thành công và có thể
khiến ứng dụng của bạn hoặc các ứng dụng khác bị tắt.
Phát hiện phần cứng máy ảnh
Nếu ứng dụng của bạn không đòi hỏi cụ thể phải có máy ảnh bằng cách dùng phần khai báo trong tệp kê khai,
cần kiểm tra xem có máy ảnh trong thời gian chạy hay không. Để kiểm tra, hãy sử dụng phương thức PackageManager.hasSystemFeature()
, như trong mã ví dụ bên dưới:
Kotlin
/** Check if this device has a camera */ private fun checkCameraHardware(context: Context): Boolean { if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)) { // this device has a camera return true } else { // no camera on this device return false } }
Java
/** Check if this device has a camera */ private boolean checkCameraHardware(Context context) { if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){ // this device has a camera return true; } else { // no camera on this device return false; } }
Các thiết bị Android có thể có nhiều máy ảnh, chẳng hạn như máy ảnh mặt sau để chụp ảnh và
máy ảnh mặt trước để gọi video. Android 2.3 (API cấp 9) trở lên cho phép bạn kiểm tra
số máy ảnh có trên một thiết bị bằng cách sử dụng phương thức Camera.getNumberOfCameras()
.
Truy cập camera
Nếu bạn xác định rằng thiết bị mà ứng dụng của bạn đang chạy có máy ảnh, bạn
phải yêu cầu truy cập bằng cách tải một thực thể của Camera
(trừ phi bạn
đang dùng một ý định truy cập vào camera).
Để truy cập vào máy ảnh chính, hãy dùng phương thức Camera.open()
và nhớ phát hiện mọi ngoại lệ như trong đoạn mã dưới đây:
Kotlin
/** A safe way to get an instance of the Camera object. */ fun getCameraInstance(): Camera? { return try { Camera.open() // attempt to get a Camera instance } catch (e: Exception) { // Camera is not available (in use or does not exist) null // returns null if camera is unavailable } }
Java
/** A safe way to get an instance of the Camera object. */ public static Camera getCameraInstance(){ Camera c = null; try { c = Camera.open(); // attempt to get a Camera instance } catch (Exception e){ // Camera is not available (in use or does not exist) } return c; // returns null if camera is unavailable }
Thận trọng: Luôn kiểm tra các trường hợp ngoại lệ khi dùng Camera.open()
. Không kiểm tra được các trường hợp ngoại lệ nếu camera đang bật
sử dụng hoặc không tồn tại sẽ khiến hệ thống tắt ứng dụng của bạn.
Trên các thiết bị chạy Android 2.3 (API cấp 9) trở lên, bạn có thể truy cập vào các camera cụ thể bằng
Camera.open(int)
. Mã ví dụ ở trên sẽ truy cập
máy ảnh mặt sau đầu tiên trên một thiết bị có nhiều máy ảnh.
Đang kiểm tra các tính năng của máy ảnh
Sau khi có quyền truy cập vào camera, bạn có thể xem thêm thông tin về các tính năng của camera bằng cách sử dụng
phương thức Camera.getParameters()
và kiểm tra
trả về đối tượng Camera.Parameters
cho các tính năng được hỗ trợ. Khi sử dụng
API cấp 9 trở lên, dùng Camera.getCameraInfo()
để xác định xem có máy ảnh ở mặt trước hay không
hoặc mặt sau của thiết bị và hướng của hình ảnh.
Tạo lớp xem trước
Để người dùng chụp ảnh hoặc quay video hiệu quả, họ phải biết được máy ảnh của thiết bị
nhìn thấy. Lớp xem trước của máy ảnh là SurfaceView
có thể hiển thị hình ảnh trực tiếp
từ máy ảnh, để người dùng có thể lấy khung hình và chụp ảnh hoặc quay video.
Mã ví dụ sau đây minh hoạ cách tạo một lớp xem trước cơ bản của máy ảnh có thể
có trong bố cục View
. Lớp này triển khai SurfaceHolder.Callback
để ghi lại các sự kiện gọi lại
để tạo và huỷ khung hiển thị, cần thiết để chỉ định đầu vào của bản xem trước của máy ảnh.
Kotlin
/** A basic Camera preview class */ class CameraPreview( context: Context, private val mCamera: Camera ) : SurfaceView(context), SurfaceHolder.Callback { private val mHolder: SurfaceHolder = holder.apply { // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. addCallback(this@CameraPreview) // deprecated setting, but required on Android versions prior to 3.0 setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS) } override fun surfaceCreated(holder: SurfaceHolder) { // The Surface has been created, now tell the camera where to draw the preview. mCamera.apply { try { setPreviewDisplay(holder) startPreview() } catch (e: IOException) { Log.d(TAG, "Error setting camera preview: ${e.message}") } } } override fun surfaceDestroyed(holder: SurfaceHolder) { // empty. Take care of releasing the Camera preview in your activity. } override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) { // If your preview can change or rotate, take care of those events here. // Make sure to stop the preview before resizing or reformatting it. if (mHolder.surface == null) { // preview surface does not exist return } // stop preview before making changes try { mCamera.stopPreview() } catch (e: Exception) { // ignore: tried to stop a non-existent preview } // set preview size and make any resize, rotate or // reformatting changes here // start preview with new settings mCamera.apply { try { setPreviewDisplay(mHolder) startPreview() } catch (e: Exception) { Log.d(TAG, "Error starting camera preview: ${e.message}") } } } }
Java
/** A basic Camera preview class */ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder mHolder; private Camera mCamera; public CameraPreview(Context context, Camera camera) { super(context); mCamera = camera; // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. mHolder = getHolder(); mHolder.addCallback(this); // deprecated setting, but required on Android versions prior to 3.0 mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } public void surfaceCreated(SurfaceHolder holder) { // The Surface has been created, now tell the camera where to draw the preview. try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); } catch (IOException e) { Log.d(TAG, "Error setting camera preview: " + e.getMessage()); } } public void surfaceDestroyed(SurfaceHolder holder) { // empty. Take care of releasing the Camera preview in your activity. } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // If your preview can change or rotate, take care of those events here. // Make sure to stop the preview before resizing or reformatting it. if (mHolder.getSurface() == null){ // preview surface does not exist return; } // stop preview before making changes try { mCamera.stopPreview(); } catch (Exception e){ // ignore: tried to stop a non-existent preview } // set preview size and make any resize, rotate or // reformatting changes here // start preview with new settings try { mCamera.setPreviewDisplay(mHolder); mCamera.startPreview(); } catch (Exception e){ Log.d(TAG, "Error starting camera preview: " + e.getMessage()); } } }
Nếu bạn muốn đặt kích thước cụ thể cho bản xem trước của máy ảnh, hãy thiết lập kích thước này trong phương thức surfaceChanged()
như đã nêu trong các nhận xét ở trên. Khi đặt kích thước xem trước, bạn
phải sử dụng các giá trị từ getSupportedPreviewSizes()
.
Không đặt các giá trị tuỳ ý trong phương thức setPreviewSize()
.
Lưu ý:
Với sự ra mắt của
Tính năng Nhiều cửa sổ trong Android 7.0 (API cấp 24) trở lên, bạn không thể
giả sử tỷ lệ khung hình của bản xem trước giống với hoạt động của bạn
ngay cả sau khi gọi setDisplayOrientation()
.
Tuỳ thuộc vào kích thước cửa sổ và tỷ lệ khung hình, bạn có thể phải lắp cỡ ảnh
bản xem trước của máy ảnh thành bố cục theo hướng dọc hoặc ngược lại, bằng cách dùng
bố cục hòm thư.
Đặt bản xem trước trong một bố cục
Bạn phải đặt một lớp xem trước của máy ảnh (chẳng hạn như ví dụ minh hoạ trong phần trước) trong phần tử bố cục của một hoạt động cùng với các chế độ điều khiển khác trên giao diện người dùng để chụp ảnh hoặc quay video. Chiến dịch này cho bạn biết cách tạo bố cục và hoạt động cơ bản cho bản xem trước.
Mã bố cục sau đây cung cấp một khung hiển thị rất cơ bản có thể dùng để hiển thị camera
bản xem trước. Trong ví dụ này, phần tử FrameLayout
được dành cho
vùng chứa cho lớp xem trước của máy ảnh. Loại bố cục này được dùng để hình ảnh bổ sung
thông tin hoặc chế độ điều khiển có thể phủ lên hình ảnh xem trước của camera trực tiếp.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" > <FrameLayout android:id="@+id/camera_preview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" /> <Button android:id="@+id/button_capture" android:text="Capture" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> </LinearLayout>
Trên hầu hết các thiết bị, hướng mặc định của bản xem trước máy ảnh là hướng ngang. Bố cục mẫu này chỉ định bố cục ngang (ngang) và mã bên dưới sửa hướng của chuyển ứng dụng sang chế độ ngang. Để đơn giản hoá việc hiển thị bản xem trước của máy ảnh, bạn nên thay đổi hướng hoạt động xem trước của ứng dụng sang hướng ngang bằng cách thêm đoạn mã sau vào tệp kê khai.
<activity android:name=".CameraActivity" android:label="@string/app_name" android:screenOrientation="landscape"> <!-- configure this activity to use landscape orientation --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
Lưu ý: Bản xem trước của máy ảnh không nhất thiết phải ở chế độ ngang.
Kể từ Android 2.2 (API cấp 8), bạn có thể sử dụng phương thức setDisplayOrientation()
để đặt giá trị
xoay hình ảnh xem trước. Để thay đổi hướng xem trước khi người dùng định hướng lại
điện thoại, trong phương thức surfaceChanged()
của lớp xem trước, trước tiên hãy dừng bản xem trước bằng cách Camera.stopPreview()
thay đổi hướng rồi
bắt đầu lại bản xem trước bằng Camera.startPreview()
.
Trong hoạt động cho chế độ xem camera, hãy thêm lớp xem trước vào phần tử FrameLayout
như ví dụ trên. Hoạt động trên camera cũng phải
hãy đảm bảo camera nhả ra khi tạm dừng hoặc tắt. Ví dụ sau đây minh hoạ cách
sửa đổi hoạt động của máy ảnh để đính kèm lớp xem trước hiển thị trong phần Tạo
lớp xem trước.
Kotlin
class CameraActivity : Activity() { private var mCamera: Camera? = null private var mPreview: CameraPreview? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Create an instance of Camera mCamera = getCameraInstance() mPreview = mCamera?.let { // Create our Preview view CameraPreview(this, it) } // Set the Preview view as the content of our activity. mPreview?.also { val preview: FrameLayout = findViewById(R.id.camera_preview) preview.addView(it) } } }
Java
public class CameraActivity extends Activity { private Camera mCamera; private CameraPreview mPreview; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Create an instance of Camera mCamera = getCameraInstance(); // Create our Preview view and set it as the content of our activity. mPreview = new CameraPreview(this, mCamera); FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview); preview.addView(mPreview); } }
Lưu ý: Phương thức getCameraInstance()
trong ví dụ trên
đề cập đến phương thức ví dụ trong phần Truy cập vào camera.
Đang chụp ảnh
Sau khi tạo lớp xem trước và bố cục thành phần hiển thị để hiển thị lớp này, bạn đã sẵn sàng bắt đầu chụp ảnh bằng ứng dụng của bạn. Trong mã xử lý ứng dụng, bạn phải thiết lập trình nghe để điều khiển giao diện người dùng nhằm phản hồi một hành động của người dùng bằng cách chụp ảnh.
Để truy xuất ảnh, hãy sử dụng phương thức Camera.takePicture()
. Phương thức này lấy 3 tham số nhận dữ liệu từ máy ảnh.
Để nhận dữ liệu ở định dạng JPEG, bạn phải triển khai giao diện Camera.PictureCallback
để nhận dữ liệu hình ảnh và
ghi vào một tệp. Đoạn mã sau đây cho thấy cách triển khai cơ bản của giao diện Camera.PictureCallback
để lưu hình ảnh nhận được từ máy ảnh.
Kotlin
private val mPicture = Camera.PictureCallback { data, _ -> val pictureFile: File = getOutputMediaFile(MEDIA_TYPE_IMAGE) ?: run { Log.d(TAG, ("Error creating media file, check storage permissions")) return@PictureCallback } try { val fos = FileOutputStream(pictureFile) fos.write(data) fos.close() } catch (e: FileNotFoundException) { Log.d(TAG, "File not found: ${e.message}") } catch (e: IOException) { Log.d(TAG, "Error accessing file: ${e.message}") } }
Java
private PictureCallback mPicture = new PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE); if (pictureFile == null){ Log.d(TAG, "Error creating media file, check storage permissions"); return; } try { FileOutputStream fos = new FileOutputStream(pictureFile); fos.write(data); fos.close(); } catch (FileNotFoundException e) { Log.d(TAG, "File not found: " + e.getMessage()); } catch (IOException e) { Log.d(TAG, "Error accessing file: " + e.getMessage()); } } };
Kích hoạt tính năng chụp ảnh bằng cách gọi phương thức Camera.takePicture()
. Đoạn mã ví dụ sau đây cho thấy cách gọi phương thức này từ một
nút View.OnClickListener
.
Kotlin
val captureButton: Button = findViewById(R.id.button_capture) captureButton.setOnClickListener { // get an image from the camera mCamera?.takePicture(null, null, picture) }
Java
// Add a listener to the Capture button Button captureButton = (Button) findViewById(R.id.button_capture); captureButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { // get an image from the camera mCamera.takePicture(null, null, picture); } } );
Lưu ý: Thành phần mPicture
trong ví dụ sau đây tham chiếu
vào mã ví dụ ở trên.
Thận trọng: Hãy nhớ phát hành Camera
bằng cách gọi Camera.release()
khi
đã sử dụng xong! Để biết thông tin về cách tháo camera, hãy xem phần Gỡ bỏ camera.
Đang quay video
Quay video bằng khung Android yêu cầu quản lý cẩn thận đối tượng Camera
và phối hợp với MediaRecorder
. Khi quay video bằng Camera
, bạn phải quản lý các lệnh gọi Camera.lock()
và Camera.unlock()
để cho phép MediaRecorder
truy cập vào phần cứng của máy ảnh,
ngoài các lệnh gọi Camera.open()
và Camera.release()
.
Lưu ý: Kể từ Android 4.0 (API cấp 14), các lệnh gọi Camera.lock()
và Camera.unlock()
sẽ được tự động quản lý cho bạn.
Không giống như chụp ảnh bằng máy ảnh của thiết bị, quay video đòi hỏi một cuộc gọi rất cụ thể đơn đặt hàng. Bạn phải tuân theo một thứ tự thực hiện cụ thể để chuẩn bị và quay video thành công với ứng dụng của bạn, như được nêu chi tiết dưới đây.
- Mở máy ảnh – Sử dụng
Camera.open()
để lấy thực thể của đối tượng camera. - Kết nối bản xem trước – Chuẩn bị bản xem trước hình ảnh của camera trực tiếp bằng cách kết nối
SurfaceView
với camera bằngCamera.setPreviewDisplay()
. - Bắt đầu xem trước – Gọi
Camera.startPreview()
để bắt đầu hiển thị hình ảnh trực tiếp của camera. - Bắt đầu quay video - Bạn phải hoàn thành các bước sau trong
đặt hàng để quay video thành công:
- Mở khoá Máy ảnh – Mở khoá máy ảnh để sử dụng trước
MediaRecorder
bằng cách gọiCamera.unlock()
. - Định cấu hình MediaRecorder – Gọi trong các phương thức
MediaRecorder
sau theo thứ tự này. Để biết thêm thông tin, hãy xem tài liệu tham khảo vềMediaRecorder
.setCamera()
– Đặt camera sẽ dùng để quay video, sử dụng phiên bản hiện tại của ứng dụng trong tổng sốCamera
.setAudioSource()
– Thiết lập nguồn âm thanh, hãy sử dụngMediaRecorder.AudioSource.CAMCORDER
.setVideoSource()
– Đặt nguồn video, hãy sử dụngMediaRecorder.VideoSource.CAMERA
.- Đặt mã hoá và định dạng đầu ra video. Dành cho Android 2.2 (API cấp 8) và
cao hơn, sử dụng phương thức
MediaRecorder.setProfile
và tạo một phiên bản hồ sơ bằngCamcorderProfile.get()
. Đối với các phiên bản Android trước 2.2, bạn phải đặt định dạng đầu ra video và các tham số mã hóa:setOutputFormat()
– Đặt định dạng đầu ra, hãy chỉ định chế độ cài đặt mặc định hoặcMediaRecorder.OutputFormat.MPEG_4
.setAudioEncoder()
– Đặt loại mã hoá âm thanh, hãy chỉ định chế độ cài đặt mặc định hoặcMediaRecorder.AudioEncoder.AMR_NB
.setVideoEncoder()
– Đặt loại mã hoá video, hãy chỉ định chế độ cài đặt mặc định hoặcMediaRecorder.VideoEncoder.MPEG_4_SP
.
setOutputFile()
– Thiết lập tệp đầu ra, sử dụnggetOutputMediaFile(MEDIA_TYPE_VIDEO).toString()
trong ví dụ trong phần Lưu tệp phương tiện.setPreviewDisplay()
– Chỉ định phần tử bố cục xem trướcSurfaceView
cho ứng dụng của bạn. Sử dụng chính đối tượng mà bạn đã chỉ định cho Bản xem trước kết nối.
Thận trọng: Bạn phải gọi các phương thức cấu hình
MediaRecorder
này theo thứ tự này, nếu không thì sẽ gặp lỗi và việc ghi sẽ không thành công. - Chuẩn bị MediaRecorder – Chuẩn bị
MediaRecorder
với chế độ cài đặt cấu hình được cung cấp bằng cách gọiMediaRecorder.prepare()
. - Khởi động MediaRecorder – Bắt đầu quay video bằng cách gọi
MediaRecorder.start()
.
- Mở khoá Máy ảnh – Mở khoá máy ảnh để sử dụng trước
- Dừng ghi video – Gọi các phương thức sau theo thứ tự để
hoàn tất thành công bản ghi video:
- Dừng MediaRecorder – Dừng quay video bằng cách gọi
MediaRecorder.stop()
. - Reset MediaRecorder – Theo tuỳ chọn, hãy xoá các cài đặt cấu hình khỏi
trình ghi bằng cách gọi
MediaRecorder.reset()
. - Phát hành MediaRecorder – Phát hành
MediaRecorder
bằng cách gọiMediaRecorder.release()
. - Khoá camera – Khoá camera để các phiên
MediaRecorder
sau này có thể sử dụng camera bằng cách gọiCamera.lock()
. Kể từ Android 4.0 (API cấp 14), lệnh gọi này là không bắt buộc trừ khi Cuộc gọiMediaRecorder.prepare()
không thành công.
- Dừng MediaRecorder – Dừng quay video bằng cách gọi
- Dừng bản xem trước – Khi hoạt động của bạn đã sử dụng xong máy ảnh, hãy dừng
bản xem trước bằng
Camera.stopPreview()
. - Phát hành camera – Thả camera để các ứng dụng khác có thể sử dụng
bằng cách gọi
Camera.release()
.
Lưu ý: Bạn có thể sử dụng MediaRecorder
mà không cần tạo bản xem trước của máy ảnh trước và bỏ qua một vài bước đầu của quá trình này. Tuy nhiên,
vì người dùng thường muốn xem trước trước khi bắt đầu ghi, nên quá trình này
thảo luận ở đây.
Mẹo: Nếu ứng dụng của bạn thường dùng để quay video, hãy thiết lập
setRecordingHint(boolean)
đến true
trước khi bắt đầu
bản xem trước. Chế độ cài đặt này có thể giúp làm giảm thời gian cần thiết để bắt đầu quay.
Định cấu hình MediaRecorder
Khi sử dụng lớp MediaRecorder
để quay video, bạn phải thực hiện
các bước định cấu hình theo thứ tự cụ thể, sau đó gọi phương thức MediaRecorder.prepare()
để kiểm tra và triển khai
. Mã ví dụ sau đây minh hoạ cách định cấu hình và chuẩn bị đúng cách
Lớp MediaRecorder
để quay video.
Kotlin
private fun prepareVideoRecorder(): Boolean { mediaRecorder = MediaRecorder() mCamera?.let { camera -> // Step 1: Unlock and set camera to MediaRecorder camera?.unlock() mediaRecorder?.run { setCamera(camera) // Step 2: Set sources setAudioSource(MediaRecorder.AudioSource.CAMCORDER) setVideoSource(MediaRecorder.VideoSource.CAMERA) // Step 3: Set a CamcorderProfile (requires API Level 8 or higher) setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)) // Step 4: Set output file setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()) // Step 5: Set the preview output setPreviewDisplay(mPreview?.holder?.surface) setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT) setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT) // Step 6: Prepare configured MediaRecorder return try { prepare() true } catch (e: IllegalStateException) { Log.d(TAG, "IllegalStateException preparing MediaRecorder: ${e.message}") releaseMediaRecorder() false } catch (e: IOException) { Log.d(TAG, "IOException preparing MediaRecorder: ${e.message}") releaseMediaRecorder() false } } } return false }
Java
private boolean prepareVideoRecorder(){ mCamera = getCameraInstance(); mediaRecorder = new MediaRecorder(); // Step 1: Unlock and set camera to MediaRecorder mCamera.unlock(); mediaRecorder.setCamera(mCamera); // Step 2: Set sources mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); // Step 3: Set a CamcorderProfile (requires API Level 8 or higher) mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)); // Step 4: Set output file mediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString()); // Step 5: Set the preview output mediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface()); // Step 6: Prepare configured MediaRecorder try { mediaRecorder.prepare(); } catch (IllegalStateException e) { Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage()); releaseMediaRecorder(); return false; } catch (IOException e) { Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage()); releaseMediaRecorder(); return false; } return true; }
Trước Android 2.2 (API cấp 8), bạn phải đặt định dạng đầu ra và định dạng mã hoá
thay vì sử dụng CamcorderProfile
. Phương pháp này
được minh hoạ trong mã sau:
Kotlin
// Step 3: Set output format and encoding (for versions prior to API Level 8) mediaRecorder?.apply { setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT) setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT) }
Java
// Step 3: Set output format and encoding (for versions prior to API Level 8) mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
Đã cung cấp các tham số quay video sau đây cho MediaRecorder
cài đặt mặc định, tuy nhiên, bạn có thể muốn điều chỉnh các cài đặt này cho ứng dụng của mình:
setVideoEncodingBitRate()
setVideoSize()
setVideoFrameRate()
setAudioEncodingBitRate()
setAudioChannels()
setAudioSamplingRate()
Khởi động và dừng MediaRecorder
Khi bắt đầu và dừng quay video bằng lớp MediaRecorder
,
bạn phải tuân theo thứ tự cụ thể, như được liệt kê dưới đây.
- Mở khoá máy ảnh bằng
Camera.unlock()
- Định cấu hình
MediaRecorder
như trong đoạn mã ví dụ ở trên - Bắt đầu quay bằng
MediaRecorder.start()
- Quay video
- Dừng quay bằng
MediaRecorder.stop()
- Phát hành trình ghi nội dung nghe nhìn bằng
MediaRecorder.release()
- Khoá camera bằng
Camera.lock()
Mã ví dụ sau đây minh hoạ cách kết nối một nút để bắt đầu và dừng đúng cách
quay video bằng máy ảnh và lớp MediaRecorder
.
Lưu ý: Khi quay video xong, không được thả máy ảnh nếu không, bản dùng thử của bạn sẽ bị dừng.
Kotlin
var isRecording = false val captureButton: Button = findViewById(R.id.button_capture) captureButton.setOnClickListener { if (isRecording) { // stop recording and release camera mediaRecorder?.stop() // stop the recording releaseMediaRecorder() // release the MediaRecorder object mCamera?.lock() // take camera access back from MediaRecorder // inform the user that recording has stopped setCaptureButtonText("Capture") isRecording = false } else { // initialize video camera if (prepareVideoRecorder()) { // Camera is available and unlocked, MediaRecorder is prepared, // now you can start recording mediaRecorder?.start() // inform the user that recording has started setCaptureButtonText("Stop") isRecording = true } else { // prepare didn't work, release the camera releaseMediaRecorder() // inform user } } }
Java
private boolean isRecording = false; // Add a listener to the Capture button Button captureButton = (Button) findViewById(id.button_capture); captureButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { if (isRecording) { // stop recording and release camera mediaRecorder.stop(); // stop the recording releaseMediaRecorder(); // release the MediaRecorder object mCamera.lock(); // take camera access back from MediaRecorder // inform the user that recording has stopped setCaptureButtonText("Capture"); isRecording = false; } else { // initialize video camera if (prepareVideoRecorder()) { // Camera is available and unlocked, MediaRecorder is prepared, // now you can start recording mediaRecorder.start(); // inform the user that recording has started setCaptureButtonText("Stop"); isRecording = true; } else { // prepare didn't work, release the camera releaseMediaRecorder(); // inform user } } } } );
Lưu ý: Trong ví dụ trên, prepareVideoRecorder()
tham chiếu đến mã mẫu được hiển thị trong phần Định cấu hình MediaRecorder. Phương thức này đảm nhận việc khoá
camera, định cấu hình và chuẩn bị thực thể MediaRecorder
.
Cách tháo camera
Camera là tài nguyên được các ứng dụng trên thiết bị chia sẻ. Ứng dụng của bạn có thể khiến
sử dụng máy ảnh sau khi nhận được thực thể của Camera
và bạn phải
đặc biệt thận trọng để giải phóng đối tượng máy ảnh khi ứng dụng của bạn ngừng sử dụng đối tượng đó và như
ngay khi ứng dụng của bạn bị tạm dừng (Activity.onPause()
). Nếu
ứng dụng của bạn không tháo camera đúng cách, tất cả các lần thử truy cập camera sau đó,
kể cả những truy vấn do chính ứng dụng của bạn tạo, sẽ không thành công và có thể khiến ứng dụng của bạn hoặc các ứng dụng khác
tắt.
Để huỷ bỏ một thực thể của đối tượng Camera
, hãy dùng phương thức Camera.release()
, như trong mã ví dụ dưới đây.
Kotlin
class CameraActivity : Activity() { private var mCamera: Camera? private var preview: SurfaceView? private var mediaRecorder: MediaRecorder? override fun onPause() { super.onPause() releaseMediaRecorder() // if you are using MediaRecorder, release it first releaseCamera() // release the camera immediately on pause event } private fun releaseMediaRecorder() { mediaRecorder?.reset() // clear recorder configuration mediaRecorder?.release() // release the recorder object mediaRecorder = null mCamera?.lock() // lock camera for later use } private fun releaseCamera() { mCamera?.release() // release the camera for other applications mCamera = null } }
Java
public class CameraActivity extends Activity { private Camera mCamera; private SurfaceView preview; private MediaRecorder mediaRecorder; ... @Override protected void onPause() { super.onPause(); releaseMediaRecorder(); // if you are using MediaRecorder, release it first releaseCamera(); // release the camera immediately on pause event } private void releaseMediaRecorder(){ if (mediaRecorder != null) { mediaRecorder.reset(); // clear recorder configuration mediaRecorder.release(); // release the recorder object mediaRecorder = null; mCamera.lock(); // lock camera for later use } } private void releaseCamera(){ if (mCamera != null){ mCamera.release(); // release the camera for other applications mCamera = null; } } }
Thận trọng: Nếu ứng dụng của bạn không phát hành đúng cách máy ảnh, tất cả những lần thử truy cập máy ảnh sau này, bao gồm cả những lần truy cập bằng ứng dụng của chính bạn sẽ bị lỗi và có thể khiến ứng dụng của bạn hoặc ứng dụng khác bị tắt.
Đang lưu tệp nội dung nghe nhìn
Các tệp nội dung nghe nhìn do người dùng tạo, chẳng hạn như ảnh và video phải được lưu vào bộ nhớ ngoài của thiết bị thư mục bộ nhớ (Thẻ SD) để tiết kiệm dung lượng hệ thống và cho phép người dùng truy cập vào các tệp này mà không cần thiết bị của họ. Có nhiều vị trí thư mục để lưu tệp đa phương tiện trên một thiết bị, tuy nhiên, chỉ có hai vị trí tiêu chuẩn mà bạn nên cân nhắc là nhà phát triển:
Environment.getExternalStoragePublicDirectory
(Environment.DIRECTORY_PICTURES
) – Phương thức này trả về giá trị tiêu chuẩn, được chia sẻ và nên dùng vị trí để lưu ảnh và video. Thư mục này được chia sẻ (công khai) nên các ứng dụng khác có thể dễ dàng khám phá, đọc, thay đổi và xoá tệp đã lưu ở vị trí này. Nếu ứng dụng của bạn là bị người dùng gỡ cài đặt, các tệp nội dung nghe nhìn được lưu vào vị trí này sẽ không bị xoá. Cần tránh can thiệp vào ảnh và video hiện có của người dùng, bạn nên tạo một thư mục con cho các tệp đa phương tiện của ứng dụng trong thư mục này, như được hiển thị trong mã mẫu bên dưới. Phương thức này có trong Android 2.2 (API cấp 8), đối với các lệnh gọi tương đương trong các phiên bản API cũ, hãy xem Lưu tệp chia sẻ.Context.getExternalFilesDir
(Environment.DIRECTORY_PICTURES
) – Phương thức này trả về vị trí chuẩn để lưu ảnh và video được liên kết với ứng dụng của bạn. Nếu ứng dụng đã bị gỡ cài đặt, mọi tệp được lưu ở vị trí này sẽ bị xoá. Bảo mật không được thực thi cho các tệp trong vị trí và các ứng dụng khác có thể đọc, thay đổi và xoá chúng.
Mã ví dụ sau đây minh hoạ cách tạo vị trí File
hoặc Uri
cho một tệp đa phương tiện có thể dùng khi gọi camera của thiết bị bằng
Intent
hoặc trong khuôn khổ Xây dựng Camera
Ứng dụng.
Kotlin
val MEDIA_TYPE_IMAGE = 1 val MEDIA_TYPE_VIDEO = 2 /** Create a file Uri for saving an image or video */ private fun getOutputMediaFileUri(type: Int): Uri { return Uri.fromFile(getOutputMediaFile(type)) } /** Create a File for saving an image or video */ private fun getOutputMediaFile(type: Int): File? { // To be safe, you should check that the SDCard is mounted // using Environment.getExternalStorageState() before doing this. val mediaStorageDir = File( Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyCameraApp" ) // This location works best if you want the created images to be shared // between applications and persist after your app has been uninstalled. // Create the storage directory if it does not exist mediaStorageDir.apply { if (!exists()) { if (!mkdirs()) { Log.d("MyCameraApp", "failed to create directory") return null } } } // Create a media file name val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date()) return when (type) { MEDIA_TYPE_IMAGE -> { File("${mediaStorageDir.path}${File.separator}IMG_$timeStamp.jpg") } MEDIA_TYPE_VIDEO -> { File("${mediaStorageDir.path}${File.separator}VID_$timeStamp.mp4") } else -> null } }
Java
public static final int MEDIA_TYPE_IMAGE = 1; public static final int MEDIA_TYPE_VIDEO = 2; /** Create a file Uri for saving an image or video */ private static Uri getOutputMediaFileUri(int type){ return Uri.fromFile(getOutputMediaFile(type)); } /** Create a File for saving an image or video */ private static File getOutputMediaFile(int type){ // To be safe, you should check that the SDCard is mounted // using Environment.getExternalStorageState() before doing this. File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES), "MyCameraApp"); // This location works best if you want the created images to be shared // between applications and persist after your app has been uninstalled. // Create the storage directory if it does not exist if (! mediaStorageDir.exists()){ if (! mediaStorageDir.mkdirs()){ Log.d("MyCameraApp", "failed to create directory"); return null; } } // Create a media file name String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); File mediaFile; if (type == MEDIA_TYPE_IMAGE){ mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_"+ timeStamp + ".jpg"); } else if(type == MEDIA_TYPE_VIDEO) { mediaFile = new File(mediaStorageDir.getPath() + File.separator + "VID_"+ timeStamp + ".mp4"); } else { return null; } return mediaFile; }
Lưu ý: Environment.getExternalStoragePublicDirectory()
có trong Android 2.2 (API cấp 8) hoặc
cao hơn. Nếu bạn đang nhắm đến các thiết bị có các phiên bản Android cũ, hãy sử dụng Environment.getExternalStorageDirectory()
thay thế. Để biết thêm thông tin, hãy xem Lưu tệp được chia sẻ.
Để URI hỗ trợ hồ sơ công việc, trước tiên
chuyển đổi URI tệp thành URI nội dung. Sau đó, hãy thêm URI nội dung vào
EXTRA_OUTPUT
của Intent
.
Để biết thêm thông tin về cách lưu tệp trên thiết bị Android, hãy xem phần Bộ nhớ dữ liệu.
Tính năng của camera
Android hỗ trợ nhiều tính năng của máy ảnh mà bạn có thể điều khiển bằng ứng dụng máy ảnh,
chẳng hạn như định dạng ảnh, chế độ flash, chế độ cài đặt lấy nét và nhiều chế độ khác. Phần này liệt kê các phương pháp
các tính năng của máy ảnh và thảo luận ngắn gọn về cách sử dụng chúng. Bạn có thể truy cập và thiết lập hầu hết các tính năng của máy ảnh
bằng cách sử dụng đối tượng thông qua Camera.Parameters
. Tuy nhiên, có một vài
các tính năng quan trọng yêu cầu nhiều chế độ cài đặt đơn giản trong Camera.Parameters
. Các tính năng này được đề cập trong những phần sau:
Để biết thông tin chung về cách sử dụng các tính năng do Camera.Parameters
kiểm soát, hãy xem bài viết Sử dụng máy ảnh
các tính năng. Để biết thêm thông tin chi tiết về cách sử dụng các tính năng được kiểm soát thông qua
đối tượng tham số camera, hãy truy cập vào các đường liên kết trong danh sách tính năng bên dưới để tham khảo API
tài liệu.
Bảng 1. Các tính năng phổ biến của máy ảnh được sắp xếp theo Cấp độ API Android mà chúng được giới thiệu.
Tính năng | Cấp độ API: | Mô tả |
---|---|---|
Phát hiện khuôn mặt | 14 | Xác định khuôn mặt người trong một hình ảnh và dùng khuôn mặt đó để lấy nét, đo sáng và lấy màu trắng số dư |
Khu vực đo sáng | 14 | Chỉ định một hoặc nhiều vùng trong hình ảnh để tính toán cân bằng trắng |
Khía cạnh trọng tâm | 14 | Đặt một hoặc nhiều vùng trong hình ảnh dùng để lấy tiêu điểm |
White Balance Lock |
14 | Dừng hoặc bắt đầu tự động điều chỉnh cân bằng trắng |
Exposure Lock |
14 | Dừng hoặc bắt đầu tính năng tự động điều chỉnh độ phơi sáng |
Video Snapshot |
14 | Chụp ảnh trong khi quay video (lấy khung hình) |
Video Tua nhanh thời gian | 11 | Quay khung hình với độ trễ đã thiết lập để quay video ở chế độ tua nhanh thời gian |
Multiple Cameras |
9 | Hỗ trợ nhiều máy ảnh trên một thiết bị, bao gồm máy ảnh mặt trước và máy ảnh mặt sau camera |
Focus Distance |
9 | Báo cáo khoảng cách giữa máy ảnh và đối tượng có vẻ như được lấy nét |
Zoom |
8 | Đặt tính năng phóng to hình ảnh |
Exposure
Compensation |
8 | Tăng hoặc giảm mức phơi sáng với ánh sáng |
GPS Data |
5 | Bao gồm hoặc bỏ qua dữ liệu vị trí địa lý cùng với hình ảnh |
White Balance |
5 | Đặt chế độ cân bằng trắng, chế độ này ảnh hưởng đến các giá trị màu trong ảnh đã chụp |
Focus Mode |
5 | Thiết lập cách máy ảnh lấy nét trên một đối tượng như tự động, cố định, macro hoặc vô cực |
Scene Mode |
5 | Áp dụng chế độ đặt trước cho một số loại tình huống chụp ảnh như ban đêm, bãi biển, tuyết hoặc cảnh dưới ánh nến |
JPEG Quality |
5 | Đặt mức nén cho hình ảnh JPEG để tăng hoặc giảm tệp đầu ra của hình ảnh chất lượng và kích thước |
Flash Mode |
5 | Bật, tắt đèn flash hoặc sử dụng chế độ cài đặt tự động |
Color Effects |
5 | Áp dụng hiệu ứng màu sắc cho ảnh đã chụp, chẳng hạn như đen trắng, tông màu nâu đỏ hoặc âm. |
Anti-Banding |
5 | Giảm hiệu ứng tạo dải màu trong độ dốc màu do nén JPEG |
Picture Format |
1 | Chỉ định định dạng tệp cho hình ảnh |
Picture Size |
1 | Chỉ định kích thước pixel của hình ảnh đã lưu |
Lưu ý: Các tính năng này không được hỗ trợ trên một số thiết bị do sự khác biệt về phần cứng và cách triển khai phần mềm. Để biết thông tin về cách kiểm tra tình trạng còn hàng của các tính năng trên thiết bị nơi ứng dụng của bạn đang chạy, hãy xem phần Kiểm tra phạm vi cung cấp tính năng.
Đang kiểm tra phạm vi cung cấp tính năng
Điều đầu tiên cần hiểu rõ khi bắt đầu sử dụng các tính năng của máy ảnh trên thiết bị Android là không phải tất cả các tính năng của máy ảnh đều được hỗ trợ trên mọi thiết bị. Ngoài ra, các thiết bị hỗ trợ có thể hỗ trợ chúng ở các mức độ khác nhau hoặc với các tuỳ chọn khác nhau. Do đó, một phần của Khi bạn phát triển một ứng dụng camera, hãy quyết định xem bạn muốn tính năng nào của camera và ở cấp độ nào. Sau khi đưa ra quyết định đó, bạn nên lên kế hoạch đưa mã vào ứng dụng máy ảnh kiểm tra xem phần cứng thiết bị có hỗ trợ những tính năng đó và bị lỗi hay không nếu một tính năng không có sẵn.
Bạn có thể kiểm tra khả năng sử dụng các tính năng của máy ảnh bằng cách lấy bản sao thông số của máy ảnh
và kiểm tra các phương thức có liên quan. Mã mẫu sau đây cho bạn biết cách lấy một
Camera.Parameters
đối tượng và kiểm tra xem máy ảnh có hỗ trợ tính năng tự động lấy nét hay không
tính năng:
Kotlin
val params: Camera.Parameters? = camera?.parameters val focusModes: List<String>? = params?.supportedFocusModes if (focusModes?.contains(Camera.Parameters.FOCUS_MODE_AUTO) == true) { // Autofocus mode is supported }
Java
// get Camera parameters Camera.Parameters params = camera.getParameters(); List<String> focusModes = params.getSupportedFocusModes(); if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) { // Autofocus mode is supported }
Bạn có thể dùng kỹ thuật nêu trên cho hầu hết các tính năng của camera. Chiến lược phát hành đĩa đơn
Đối tượng Camera.Parameters
cung cấp phương thức getSupported...()
, is...Supported()
hoặc getMax...()
để xác định xem một tính năng có phù hợp (và trong phạm vi nào) hay không
được hỗ trợ.
Nếu ứng dụng của bạn cần một số tính năng máy ảnh nhất định để hoạt động đúng cách, bạn có thể yêu cầu chúng thông qua việc bổ sung vào tệp kê khai ứng dụng. Khi bạn khai báo việc sử dụng thông tin cụ thể các tính năng của máy ảnh, chẳng hạn như đèn flash và tự động lấy nét, Google Play sẽ hạn chế ứng dụng của bạn được cài đặt trên các thiết bị không hỗ trợ những tính năng này. Để biết danh sách các tính năng của máy ảnh có thể được khai báo trong tệp kê khai ứng dụng của bạn, hãy xem tệp kê khai Tính năng Tệp đối chiếu.
Sử dụng các tính năng của máy ảnh
Hầu hết các tính năng của máy ảnh đều được kích hoạt và điều khiển bằng đối tượng Camera.Parameters
. Bạn có được đối tượng này bằng cách nhận thực thể của
đối tượng Camera
, gọi phương thức getParameters()
, thay đổi tham số được trả về
rồi đặt đối tượng đó trở lại đối tượng máy ảnh, như minh hoạ trong ví dụ sau
mã:
Kotlin
val params: Camera.Parameters? = camera?.parameters params?.focusMode = Camera.Parameters.FOCUS_MODE_AUTO camera?.parameters = params
Java
// get Camera parameters Camera.Parameters params = camera.getParameters(); // set the focus mode params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); // set Camera parameters camera.setParameters(params);
Kỹ thuật này áp dụng cho hầu hết các tính năng của camera và bạn có thể thay đổi hầu hết các thông số bất cứ lúc nào
sau khi bạn nhận được thực thể của đối tượng Camera
. Các thay đổi đối với
các tham số thường hiển thị cho người dùng ngay lập tức trong bản xem trước của máy ảnh của ứng dụng.
Về phía phần mềm, các thay đổi về tham số có thể mất một vài khung hình mới thực sự có hiệu lực khi
phần cứng của máy ảnh sẽ xử lý các hướng dẫn mới rồi gửi dữ liệu hình ảnh đã cập nhật.
Lưu ý quan trọng: Bạn không thể tuỳ ý thay đổi một số tính năng của camera. Trong cụ thể, việc thay đổi kích thước hoặc hướng của bản xem trước của máy ảnh trước tiên đòi hỏi bạn phải dừng xem trước, thay đổi kích thước xem trước rồi bắt đầu lại bản xem trước. Kể từ Android 4.0 (API Cấp 14) có thể thay đổi hướng xem trước mà không cần bắt đầu lại bản xem trước.
Các tính năng khác của máy ảnh yêu cầu nhiều mã hơn để triển khai, bao gồm:
- Phạm vi đo sáng và trọng tâm
- Phát hiện khuôn mặt
- Video ở chế độ tua nhanh thời gian
Tóm tắt nhanh về cách triển khai các tính năng này được cung cấp trong những phần sau.
Phạm vi đo sáng và trọng tâm
Trong một số tình huống chụp ảnh, chế độ lấy nét tự động và đo sáng có thể không tạo ra kết quả mong muốn. Kể từ Android 4.0 (API cấp 14), ứng dụng máy ảnh của bạn có thể cung cấp các chế độ kiểm soát khác giúp ứng dụng hoặc người dùng chỉ định các vùng trong một hình ảnh dùng để xác định cài đặt tiêu điểm hoặc mức ánh sáng rồi truyền các giá trị này đến phần cứng máy ảnh để dùng khi chụp ảnh hình ảnh hoặc video.
Các vùng đo sáng và lấy nét hoạt động rất giống với các tính năng khác của camera, ở chỗ bạn kiểm soát
thông qua các phương thức trong đối tượng Camera.Parameters
. Mã sau đây
minh hoạ việc đặt hai khu vực đo sáng cho một trường hợp
Camera
:
Kotlin
// Create an instance of Camera camera = getCameraInstance() // set Camera parameters val params: Camera.Parameters? = camera?.parameters params?.apply { if (maxNumMeteringAreas > 0) { // check that metering areas are supported meteringAreas = ArrayList<Camera.Area>().apply { val areaRect1 = Rect(-100, -100, 100, 100) // specify an area in center of image add(Camera.Area(areaRect1, 600)) // set weight to 60% val areaRect2 = Rect(800, -1000, 1000, -800) // specify an area in upper right of image add(Camera.Area(areaRect2, 400)) // set weight to 40% } } camera?.parameters = this }
Java
// Create an instance of Camera camera = getCameraInstance(); // set Camera parameters Camera.Parameters params = camera.getParameters(); if (params.getMaxNumMeteringAreas() > 0){ // check that metering areas are supported List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>(); Rect areaRect1 = new Rect(-100, -100, 100, 100); // specify an area in center of image meteringAreas.add(new Camera.Area(areaRect1, 600)); // set weight to 60% Rect areaRect2 = new Rect(800, -1000, 1000, -800); // specify an area in upper right of image meteringAreas.add(new Camera.Area(areaRect2, 400)); // set weight to 40% params.setMeteringAreas(meteringAreas); } camera.setParameters(params);
Đối tượng Camera.Area
chứa 2 tham số dữ liệu: Đối tượng Rect
để chỉ định một vùng trong trường nhìn của máy ảnh và trọng lượng
giá trị này cho camera biết mức độ quan trọng của khu vực này trong định mức ánh sáng
hoặc tính toán trọng tâm.
Trường Rect
trong đối tượng Camera.Area
mô tả một hình chữ nhật được lập bản đồ trên lưới đơn vị 2000 x 2000. Toạ độ -1000, -1000
biểu thị góc trên cùng, bên trái của ảnh máy ảnh, còn toạ độ 1000, 1000 biểu thị
góc dưới cùng bên phải của hình ảnh camera, như được minh hoạ bên dưới.
Hình 1. Các đường màu đỏ minh hoạ hệ thống toạ độ để chỉ định
Camera.Area
trong bản xem trước của máy ảnh. Hộp màu xanh dương hiện vị trí và
hình dạng của một khu vực camera với các giá trị Rect
là 333.333.667.667.
Các giới hạn của hệ toạ độ này luôn tương ứng với cạnh ngoài của hình ảnh có thể nhìn thấy trong
bản xem trước của máy ảnh và không thu nhỏ hoặc mở rộng theo mức thu phóng. Tương tự, xoay hình ảnh
bản xem trước bằng Camera.setDisplayOrientation()
không tạo lại bản đồ cho hệ toạ độ.
Phát hiện khuôn mặt
Đối với những bức ảnh có con người, khuôn mặt thường là phần quan trọng nhất của bức ảnh và cần được sử dụng để xác định cả tiêu điểm và cân bằng trắng khi chụp ảnh. Android 4.0 Khung (API cấp 14) cung cấp các API để xác định khuôn mặt và tính toán các chế độ cài đặt hình ảnh bằng công nghệ nhận dạng khuôn mặt.
Lưu ý: Khi tính năng phát hiện khuôn mặt đang chạy,
setWhiteBalance(String)
,
setFocusAreas(List<Camera.Area>)
và
setMeteringAreas(List<Camera.Area>)
không có hiệu lực.
Để sử dụng tính năng phát hiện khuôn mặt trong ứng dụng camera, bạn cần thực hiện một vài bước chung:
- Kiểm tra để chắc chắn rằng thiết bị có hỗ trợ tính năng phát hiện khuôn mặt
- Tạo trình nghe phát hiện khuôn mặt
- Thêm trình nghe phát hiện khuôn mặt vào đối tượng máy ảnh
- Bắt đầu phát hiện khuôn mặt sau khi bản xem trước (và sau mỗi lần khởi động lại bản xem trước)
Tính năng phát hiện khuôn mặt không được hỗ trợ trên một số thiết bị. Bạn có thể kiểm tra để đảm bảo tính năng này
được hỗ trợ bằng cách gọi getMaxNumDetectedFaces()
. Một
ví dụ về bước kiểm tra này được thể hiện trong phương thức mẫu startFaceDetection()
bên dưới.
Để nhận thông báo và phản hồi khi phát hiện khuôn mặt, ứng dụng camera phải đặt
trình nghe sự kiện phát hiện khuôn mặt. Để thực hiện việc này, bạn phải tạo một lớp trình nghe
triển khai giao diện Camera.FaceDetectionListener
như minh hoạ trong
mã ví dụ bên dưới.
Kotlin
internal class MyFaceDetectionListener : Camera.FaceDetectionListener { override fun onFaceDetection(faces: Array<Camera.Face>, camera: Camera) { if (faces.isNotEmpty()) { Log.d("FaceDetection", ("face detected: ${faces.size}" + " Face 1 Location X: ${faces[0].rect.centerX()}" + "Y: ${faces[0].rect.centerY()}")) } } }
Java
class MyFaceDetectionListener implements Camera.FaceDetectionListener { @Override public void onFaceDetection(Face[] faces, Camera camera) { if (faces.length > 0){ Log.d("FaceDetection", "face detected: "+ faces.length + " Face 1 Location X: " + faces[0].rect.centerX() + "Y: " + faces[0].rect.centerY() ); } } }
Sau khi tạo lớp này, bạn đặt lớp này vào
Đối tượng Camera
, như trong mã ví dụ bên dưới:
Kotlin
camera?.setFaceDetectionListener(MyFaceDetectionListener())
Java
camera.setFaceDetectionListener(new MyFaceDetectionListener());
Ứng dụng của bạn phải bắt đầu chức năng phát hiện khuôn mặt mỗi khi bạn khởi động (hoặc khởi động lại) bản xem trước từ camera. Tạo một phương thức để bắt đầu phát hiện khuôn mặt sao cho bạn có thể gọi tính năng này khi cần thiết, như minh hoạ trong mã ví dụ bên dưới.
Kotlin
fun startFaceDetection() { // Try starting Face Detection val params = mCamera?.parameters // start face detection only *after* preview has started params?.apply { if (maxNumDetectedFaces > 0) { // camera supports face detection, so can start it: mCamera?.startFaceDetection() } } }
Java
public void startFaceDetection(){ // Try starting Face Detection Camera.Parameters params = mCamera.getParameters(); // start face detection only *after* preview has started if (params.getMaxNumDetectedFaces() > 0){ // camera supports face detection, so can start it: mCamera.startFaceDetection(); } }
Bạn phải bắt đầu phát hiện khuôn mặt mỗi khi bắt đầu (hoặc khởi động lại) bản xem trước của camera. Nếu
bạn sử dụng lớp xem trước được hiển thị trong phần Tạo lớp xem trước, hãy thêm
startFaceDetection()
vào cả phương thức
Phương thức surfaceCreated()
và surfaceChanged()
trong lớp xem trước của bạn,
như minh hoạ trong mã mẫu bên dưới.
Kotlin
override fun surfaceCreated(holder: SurfaceHolder) { try { mCamera.setPreviewDisplay(holder) mCamera.startPreview() startFaceDetection() // start face detection feature } catch (e: IOException) { Log.d(TAG, "Error setting camera preview: ${e.message}") } } override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) { if (holder.surface == null) { // preview surface does not exist Log.d(TAG, "holder.getSurface() == null") return } try { mCamera.stopPreview() } catch (e: Exception) { // ignore: tried to stop a non-existent preview Log.d(TAG, "Error stopping camera preview: ${e.message}") } try { mCamera.setPreviewDisplay(holder) mCamera.startPreview() startFaceDetection() // re-start face detection feature } catch (e: Exception) { // ignore: tried to stop a non-existent preview Log.d(TAG, "Error starting camera preview: ${e.message}") } }
Java
public void surfaceCreated(SurfaceHolder holder) { try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); startFaceDetection(); // start face detection feature } catch (IOException e) { Log.d(TAG, "Error setting camera preview: " + e.getMessage()); } } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { if (holder.getSurface() == null){ // preview surface does not exist Log.d(TAG, "holder.getSurface() == null"); return; } try { mCamera.stopPreview(); } catch (Exception e){ // ignore: tried to stop a non-existent preview Log.d(TAG, "Error stopping camera preview: " + e.getMessage()); } try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); startFaceDetection(); // re-start face detection feature } catch (Exception e){ // ignore: tried to stop a non-existent preview Log.d(TAG, "Error starting camera preview: " + e.getMessage()); } }
Lưu ý: Hãy nhớ gọi phương thức này sau khi gọi
startPreview()
. Không cố bắt đầu phát hiện khuôn mặt
trong phương thức onCreate()
của hoạt động chính trong ứng dụng máy ảnh,
vì chưa có bản xem trước vào thời điểm này trong quá trình thực thi của ứng dụng.
Video ở chế độ tua nhanh thời gian
Video tua nhanh thời gian cho phép người dùng tạo các đoạn video kết hợp các bức ảnh được chụp vài giây hoặc
phút. Tính năng này sử dụng MediaRecorder
để ghi lại hình ảnh trong một khoảng thời gian
trình tự tua nhanh.
Để quay video ở chế độ tua nhanh thời gian bằng MediaRecorder
, bạn phải định cấu hình
như thể bạn đang quay một video thông thường, việc đặt số khung hình/giây đã chụp thành
thấp và sử dụng một trong các chế độ cài đặt chất lượng tua nhanh thời gian, như trong mã ví dụ bên dưới.
Kotlin
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH)) mediaRecorder.setCaptureRate(0.1) // capture a frame every 10 seconds
Java
// Step 3: Set a CamcorderProfile (requires API Level 8 or higher) mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH)); ... // Step 5.5: Set the video capture rate to a low number mediaRecorder.setCaptureRate(0.1); // capture a frame every 10 seconds
Các chế độ cài đặt này phải được thực hiện trong một quy trình định cấu hình lớn hơn cho MediaRecorder
. Để xem ví dụ về mã cấu hình đầy đủ, hãy xem phần Định cấu hình MediaRecorder. Sau khi quá trình định cấu hình hoàn tất,
bạn bắt đầu quay video như đang quay một đoạn video thông thường. Thông tin khác
về cách định cấu hình và chạy MediaRecorder
, hãy xem Quay video.
Camera2Video và HdrViewfinder mẫu minh hoạ thêm về việc sử dụng các API được đề cập trên trang này.
Các trường máy ảnh yêu cầu quyền
Ứng dụng chạy Android 10 (API cấp 29) trở lên phải có
Quyền CAMERA
để
truy cập vào các giá trị của các trường sau đây
getCameraCharacteristics()
phương thức trả về:
LENS_POSE_ROTATION
LENS_POSE_TRANSLATION
LENS_INTRINSIC_CALIBRATION
LENS_RADIAL_DISTORTION
LENS_POSE_REFERENCE
LENS_DISTORTION
LENS_INFO_HYPERFOCAL_DISTANCE
LENS_INFO_MINIMUM_FOCUS_DISTANCE
SENSOR_REFERENCE_ILLUMINANT1
SENSOR_REFERENCE_ILLUMINANT2
SENSOR_CALIBRATION_TRANSFORM1
SENSOR_CALIBRATION_TRANSFORM2
SENSOR_COLOR_TRANSFORM1
SENSOR_COLOR_TRANSFORM2
SENSOR_FORWARD_MATRIX1
SENSOR_FORWARD_MATRIX2
Các đoạn mã mẫu khác
Để tải ứng dụng mẫu xuống, hãy xem Mẫu Camera2Basic và Ứng dụng mẫu CameraX chính thức.