Một hệ thống quay video thường ghi lại các luồng video và âm thanh, nén các luồng đó, kết hợp 2 luồng rồi ghi luồng kết quả vào ổ đĩa.
Trong CameraX, giải pháp quay video là trường hợp sử dụng VideoCapture
:
Như minh hoạ trong hình 2, chức năng quay video của CameraX có bao gồm một số thành phần cấu trúc cấp cao:
SurfaceProvider
cho nguồn video.AudioSource
cho nguồn âm thanh.- 2 bộ mã hoá để mã hoá và nén video/âm thanh.
- Một trình kết hợp nội dung đa phương tiện để kết hợp 2 luồng.
- Một trình lưu tệp để ghi kết quả.
API VideoCapture trừu tượng hoá công cụ quay video phức tạp và mang lại cho các ứng dụng một API đơn giản và dễ hiểu hơn nhiều.
Tổng quan về API VideoCapture
VideoCapture
là một trường hợp sử dụng của CameraX, hoạt động độc lập hoặc được kết hợp với các trường hợp sử dụng khác. Những cách kết hợp cụ thể được hỗ trợ phụ thuộc vào chức năng phần cứng của máy ảnh. Tuy nhiên, Preview
và VideoCapture
là cách kết hợp trường hợp sử dụng hợp lệ trên mọi thiết bị.
API VideoCapture bao gồm những đối tượng sau để kết nối với các ứng dụng:
VideoCapture
là lớp trường hợp sử dụng cấp cao nhất.VideoCapture
liên kết vớiLifecycleOwner
bằngCameraSelector
và các UseCase khác của CameraX. Để biết thêm thông tin về những khái niệm và cách sử dụng này, hãy xem bài viết Cấu trúc CameraX.Recorder
là một cách triển khai VideoOutput được kết hợp chặt chẽ vớiVideoCapture
.Recorder
được dùng để thực hiện quá trình quay video và ghi âm thanh. Một ứng dụng tạo bản ghi từRecorder
.PendingRecording
sẽ định cấu hình bản ghi, cung cấp các tuỳ chọn như bật âm thanh và đặt trình nghe sự kiện. Bạn phải dùngRecorder
để tạoPendingRecording
.PendingRecording
không ghi lại nội dung nào.Recording
thực hiện quá trình ghi thực tế. Bạn phải dùngPendingRecording
để tạoRecording
.
Hình 3 cho thấy mối quan hệ giữa các đối tượng này:
Chú giải:
- Tạo
Recorder
bằngQualitySelector
. - Định cấu hình
Recorder
bằng một trong cácOutputOptions
. - Bật âm thanh bằng
withAudioEnabled()
nếu cần. - Gọi
start()
bằng trình ngheVideoRecordEvent
để bắt đầu quay video. - Sử dụng
pause()
/resume()
/stop()
trênRecording
để điều khiển quá trình quay video. - Phản hồi
VideoRecordEvents
bên trong trình nghe sự kiện.
Danh sách API chi tiết nằm ở current.txt bên trong mã nguồn.
Sử dụng API VideoCapture
Để tích hợp trường hợp sử dụng VideoCapture
của CameraX vào ứng dụng của bạn, hãy làm như sau:
- Liên kết
VideoCapture
. - Chuẩn bị và định cấu hình quá trình quay video.
- Bắt đầu và điều khiển quá trình quay video trong thời gian chạy.
Các phần sau đây trình bày những việc bạn có thể làm ở mỗi bước để thực hiện phiên quay video hai đầu.
Liên kết VideoCapture
Để liên kết trường hợp sử dụng VideoCapure
, hãy làm như sau:
- Tạo đối tượng
Recorder
. - Tạo đối tượng
VideoCapture
. - Liên kết với
Lifecycle
.
API VideoCapture của CameraX tuân theo mẫu thiết kế của trình tạo. Các ứng dụng dùng Recorder.Builder
để tạo Recorder
. Bạn cũng có thể định cấu hình độ phân giải video cho Recorder
thông qua đối tượng QualitySelector
.
Recorder
của CameraX hỗ trợ các Qualities
định sẵn sau đây cho độ phân giải video:
Quality.UHD
cho kích thước video độ nét siêu cao 4K (2160p)Quality.FHD
cho kích thước video HD đầy đủ (1080p)Quality.HD
cho kích thước video HD (720p)Quality.SD
cho kích thước video SD (480p)
Lưu ý rằng CameraX cũng có thể chọn những độ phân giải khác khi được ứng dụng cho phép.
Kích thước video chính xác của từng lựa chọn phụ thuộc vào chức năng của máy ảnh và bộ mã hoá. Để biết thêm thông tin, hãy xem tài liệu về CamcorderProfile
.
Các ứng dụng có thể định cấu hình độ phân giải bằng cách tạo một QualitySelector
.
Bạn có thể tạo QualitySelector
bằng một trong các phương thức sau đây:
Hãy cung cấp một vài độ phân giải ưu tiên bằng cách sử dụng
fromOrderedList()
, đồng thời thêm chiến lược dự phòng để dùng trong trường hợp không có độ phân giải ưu tiên nào được hỗ trợ.CameraX có thể quyết định độ phân giải dự phòng phù hợp nhất dựa trên chức năng của máy ảnh đã chọn, hãy tham khảo
FallbackStrategy specification
củaQualitySelector
để biết thêm thông tin chi tiết. Ví dụ: mã sau đây yêu cầu độ phân giải cao nhất được hỗ trợ để quay video. Nếu không có độ phân giải yêu cầu nào được hỗ trợ, hãy cho phép CameraX chọn độ phân giải gần nhất với độ phân giải Quality.SD:val qualitySelector = QualitySelector.fromOrderedList( listOf(Quality.UHD, Quality.FHD, Quality.HD, Quality.SD), FallbackStrategy.lowerQualityOrHigherThan(Quality.SD))
Trước tiên, hãy truy vấn chức năng của máy ảnh rồi chọn trong số những độ phân giải được hỗ trợ bằng cách sử dụng
QualitySelector::from()
:val cameraInfo = cameraProvider.availableCameraInfos.filter { Camera2CameraInfo .from(it) .getCameraCharacteristic(CameraCharacteristics.LENS\_FACING) == CameraMetadata.LENS_FACING_BACK } val supportedQualities = QualitySelector.getSupportedQualities(cameraInfo[0]) val filteredQualities = arrayListOf (Quality.UHD, Quality.FHD, Quality.HD, Quality.SD) .filter { supportedQualities.contains(it) } // Use a simple ListView with the id of simple_quality_list_view viewBinding.simpleQualityListView.apply { adapter = ArrayAdapter(context, android.R.layout.simple_list_item_1, filteredQualities.map { it.qualityToString() }) // Set up the user interaction to manually show or hide the system UI. setOnItemClickListener { _, _, position, _ -> // Inside View.OnClickListener, // convert Quality.* constant to QualitySelector val qualitySelector = QualitySelector.from(filteredQualities[position]) // Create a new Recorder/VideoCapture for the new quality // and bind to lifecycle val recorder = Recorder.Builder() .setQualitySelector(qualitySelector).build() // ... } } // A helper function to translate Quality to a string fun Quality.qualityToString() : String { return when (this) { Quality.UHD -> "UHD" Quality.FHD -> "FHD" Quality.HD -> "HD" Quality.SD -> "SD" else -> throw IllegalArgumentException() } }
Lưu ý rằng chức năng trả về từ
QualitySelector.getSupportedQualities()
được đảm bảo sẽ hoạt động cho trường hợp sử dụngVideoCapture
hoặc sự kết hợp giữa trường hợp sử dụngVideoCapture
vàPreview
. Khi liên kết với nhau bằng trường hợp sử dụngImageCapture
hoặcImageAnalysis
, CameraX có thể vẫn không liên kết được khi cách kết hợp yêu cầu không được hỗ trợ trên máy ảnh yêu cầu.
Sau khi bạn có QualitySelector
, ứng dụng có thể tạo một đối tượng VideoCapture
và thực hiện quá trình liên kết đó. Xin lưu ý rằng việc liên kết này giống với các trường hợp sử dụng khác:
val recorder = Recorder.Builder()
.setExecutor(cameraExecutor).setQualitySelector(qualitySelector)
.build()
val videoCapture = VideoCapture.withOutput(recorder)
try {
// Bind use cases to camera
cameraProvider.bindToLifecycle(
this, CameraSelector.DEFAULT_BACK_CAMERA, preview, videoCapture)
} catch(exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}
Lưu ý rằng bindToLifecycle()
sẽ trả về một đối tượng Camera
. Hãy xem hướng dẫn này để biết thêm thông tin về cách kiểm soát đầu ra của máy ảnh, chẳng hạn như thu phóng và độ phơi sáng.
Recorder
sẽ chọn định dạng phù hợp nhất với hệ thống. Bộ mã hóa và giải mã video phổ biến nhất là H.264 AVC) có định dạng vùng chứa MPEG-4.
Định cấu hình và tạo bản ghi
Từ Recorder
, ứng dụng có thể tạo các đối tượng quay video để thực hiện quá trình quay video và ghi âm thanh. Các ứng dụng tạo bản ghi bằng cách làm như sau:
- Định cấu hình
OutputOptions
bằngprepareRecording()
. - (Không bắt buộc) Bật tính năng ghi âm.
- Sử dụng
start()
để đăng ký trình ngheVideoRecordEvent
và bắt đầu quay video.
Recorder
sẽ trả về đối tượng Recording
khi bạn gọi hàm start()
.
Ứng dụng của bạn có thể dùng đối tượng Recording
này để hoàn tất quá trình quay video hoặc thực hiện các thao tác khác, chẳng hạn như tạm dừng hoặc tiếp tục.
Mỗi lần, Recorder
hỗ trợ một đối tượng Recording
. Bạn có thể bắt đầu quá trình quay video mới sau khi gọi Recording.stop()
hoặc Recording.close()
trên đối tượng Recording
trước đó.
Hãy cùng tìm hiểu chi tiết các bước này. Trước tiên, ứng dụng sẽ định cấu hình OutputOptions
cho Trình ghi bằng Recorder.prepareRecording()
.
Recorder
hỗ trợ các loại OutputOptions
sau:
FileDescriptorOutputOptions
để ghi vàoFileDescriptor
.FileOutputOptions
để ghi vàoFile
.MediaStoreOutputOptions
để ghi vàoMediaStore
.
Mọi loại OutputOptions
đều cho phép bạn đặt kích thước tệp tối đa bằng setFileSizeLimit()
. Các tuỳ chọn khác dành riêng cho từng loại đầu ra, chẳng hạn như ParcelFileDescriptor
cho FileDescriptorOutputOptions
.
prepareRecording()
sẽ trả về một đối tượng PendingRecording
. Đây là đối tượng trung gian dùng để tạo đối tượng Recording
tương ứng. PendingRecording
là một lớp tạm thời. Lớp này sẽ không hiển thị trong hầu hết các trường hợp và hiếm khi được ứng dụng lưu vào bộ nhớ đệm.
Các ứng dụng có thể định cấu hình thêm bản ghi, chẳng hạn như:
- Bật âm thanh bằng
withAudioEnabled()
. - Đăng ký một trình nghe để nhận các sự kiện quay video bằng
start(Executor, Consumer<VideoRecordEvent>)
. - Dùng
PendingRecording.asPersistentRecording()
để cho phép một bản ghi quay liên tục trong khi VideoCapture đính kèm bản ghi đó được chuyển lại một camera khác.
Để bắt đầu quay video, hãy gọi PendingRecording.start()
. CameraX sẽ chuyển PendingRecording
thành Recording
, đưa yêu cầu quay video vào hàng đợi và trả về đối tượng Recording
mới tạo cho ứng dụng.
Sau khi quá trình quay video bắt đầu trên thiết bị Máy ảnh tương ứng, CameraX sẽ gửi một sự kiện VideoRecordEvent.EVENT_TYPE_START
.
Ví dụ sau đây cho biết cách quay video và ghi âm thanh vào tệp MediaStore
:
// Create MediaStoreOutputOptions for our recorder
val name = "CameraX-recording-" +
SimpleDateFormat(FILENAME_FORMAT, Locale.US)
.format(System.currentTimeMillis()) + ".mp4"
val contentValues = ContentValues().apply {
put(MediaStore.Video.Media.DISPLAY_NAME, name)
}
val mediaStoreOutput = MediaStoreOutputOptions.Builder(this.contentResolver,
MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
.setContentValues(contentValues)
.build()
// 2. Configure Recorder and Start recording to the mediaStoreOutput.
val recording = videoCapture.output
.prepareRecording(context, mediaStoreOutput)
.withAudioEnabled()
.start(ContextCompat.getMainExecutor(this), captureListener)
Mặc dù bản xem trước của camera được phản chiếu trên camera trước theo mặc định nhưng video quay bằng VideoCapture lại không như vậy. Với CameraX 1.3, giờ đây, bạn có thể phản chiếu các bản ghi video để bản xem trước của camera trước và video đã quay trùng khớp nhau.
Có 3 lựa chọn MirrorMode: MIRROR_MODE_OFF, MIRROR_MODE_ON và MIRROR_MODE_ON_FRONT_ONLY. Để phù hợp với bản xem trước của camera, Google đề xuất sử dụng MIROR_MODE_ON_FRONT_ONLY, tức là tính năng phản chiếu không được bật cho camera sau nhưng lại được bật cho camera trước. Để biết thêm thông tin về MirrorMode, hãy xem MirrorMode constants
.
Đoạn mã này cho biết cách gọi VideoCapture.Builder.setMirrorMode()
bằng MIRROR_MODE_ON_FRONT_ONLY
. Để biết thêm thông tin, hãy xem setMirrorMode()
.
Kotlin
val recorder = Recorder.Builder().build() val videoCapture = VideoCapture.Builder(recorder) .setMirrorMode(MIRROR_MODE_ON_FRONT_ONLY) .build() useCases.add(videoCapture);
Java
Recorder.Builder builder = new Recorder.Builder(); if (mVideoQuality != QUALITY_AUTO) { builder.setQualitySelector( QualitySelector.from(mVideoQuality)); } VideoCapture<Recorder> videoCapture = new VideoCapture.Builder<>(builder.build()) .setMirrorMode(MIRROR_MODE_ON_FRONT_ONLY) .build(); useCases.add(videoCapture);
Điều khiển quá trình quay video đang hoạt động
Bạn có thể tạm dừng, tiếp tục và dừng Recording
đang diễn ra thông qua các phương thức sau:
pause
để tạm dừng quá trình quay video đang hoạt động.resume()
để tiếp tục quá trình quay video đã tạm dừng.stop()
để hoàn tất quá trình quay video và xoá mọi đối tượng quay video liên quan.mute()
để tắt hoặc bật tiếng bản ghi video hiện tại.
Xin lưu ý rằng bạn có thể gọi stop()
để chấm dứt Recording
, bất kể quá trình quay video ở trạng thái đã tạm dừng hay đang hoạt động.
Nếu bạn đã đăng ký EventListener
bằng PendingRecording.start()
, thì Recording
sẽ giao tiếp thông qua VideoRecordEvent
.
VideoRecordEvent.EVENT_TYPE_STATUS
được dùng cho số liệu thống kê quay video, chẳng hạn như kích thước tệp hiện tại và khoảng thời gian được quay.VideoRecordEvent.EVENT_TYPE_FINALIZE
được dùng cho kết quả quay video và bao gồm thông tin như URI của tệp cuối cùng kèm theo mọi lỗi liên quan.
Sau khi ứng dụng của bạn nhận được EVENT_TYPE_FINALIZE
cho biết phiên quay video thành công, bạn có thể truy cập vào video đã quay từ vị trí được chỉ định trong OutputOptions
.
Tài nguyên khác
Để tìm hiểu thêm về CameraX, hãy xem các tài nguyên bổ sung sau đây:
- Bắt đầu với Lớp học lập trình về CameraX
- Ứng dụng mẫu CameraX chính thức
- Danh sách mới nhất về API Quay video của CameraX
- Ghi chú phát hành của CameraX
- Mã nguồn CameraX