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:
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:
SurfaceProvidercho nguồn video.AudioSourcecho 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:
VideoCapturelà lớp trường hợp sử dụng cấp cao nhất.VideoCaptureliên kết vớiLifecycleOwnerbằngCameraSelectorvà 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.Recorderlà 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.PendingRecordingsẽ đị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.PendingRecordingkhông ghi lại nội dung nào.Recordingthự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
RecorderbằngQualitySelector. - Định cấu hình
Recorderbằ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
VideoRecordEventsbê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.UHDcho kích thước video độ nét siêu cao 4K (2160p)Quality.FHDcho kích thước video HD đầy đủ (1080p)Quality.HDcho kích thước video HD (720p)Quality.SDcho 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 specificationcủ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ụngVideoCapturehoặc sự kết hợp giữa trường hợp sử dụngVideoCapturevàPreview. Khi liên kết với nhau bằng trường hợp sử dụngImageCapturehoặ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
OutputOptionsbằngprepareRecording(). - (Không bắt buộc) Bật tính năng ghi âm.
- Sử dụng
start()để đăng ký trình ngheVideoRecordEventvà 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