谷歌已经发布了作为Jetpack一部分的新CameraX库。它看起来非常适合拍照,但我的用例还需要制作视频。我尝试通过谷歌搜索相关信息,但没有找到任何内容。
所以,使用CameraX Jetpack库是否可以录制视频呢?
谷歌已经发布了作为Jetpack一部分的新CameraX库。它看起来非常适合拍照,但我的用例还需要制作视频。我尝试通过谷歌搜索相关信息,但没有找到任何内容。
所以,使用CameraX Jetpack库是否可以录制视频呢?
可以使用CameraX
录制视频。我已经尝试过使用CameraX的Github演示来实现录制视频。请参考下面的代码,希望能对您有所帮助。
CameraX中的视频配置:
val videoCaptureConfig = VideoCaptureConfig.Builder().apply {
setLensFacing(lensFacing)
setTargetAspectRatio(screenAspectRatio)
setTargetRotation(viewFinder.display.rotation)
}.build()
videoCapture = VideoCapture(videoCaptureConfig)
CameraX.bindToLifecycle(this, preview, imageCapture, videoCapture)
开始录制视频:
videoCapture?.startRecording(videoFile, object : VideoCapture.OnVideoSavedListener {
override fun onVideoSaved(file: File?) {
Log.i(javaClass.simpleName, "Video File : $file")
}
override fun onError(useCaseError: VideoCapture.UseCaseError?, message: String?, cause: Throwable?) {
Log.i(javaClass.simpleName, "Video Error: $message")
}
})
停止视频录制:
videoCapture?.stopRecording()
我在Github的评论中提到了同样的问题:https://github.com/android/camera/issues/2#issuecomment-490773932
注意:使用
CameraX
实现视频录制的代码可能与上述代码有所不同。因为这段代码是我独立开发的,没有参考其他任何资料,只有Github Demo。请查看Oscar Wahltinez于2019年5月14日发表的重要评论
更新 Patel Pinkal 的答案。 由于已经发布了 beta 版本,我们不能再使用 VideoCaptureConfig.Builder(),相反,你可以采用以下方式:
videoCapture = VideoCapture.Builder().apply {
// init config here
}.build()
这是我的解决方案
//Versions in Gradle
def camerax_version = "1.0.0-beta06"
def camera_extensions = "1.0.0-alpha13"
private lateinit var videoCapture: VideoCapture
private lateinit var viewFinder: PreviewView
private lateinit var outputDirectory: File
private var lensFacing: Int = CameraSelector.LENS_FACING_FRONT
private val executor = Executors.newSingleThreadExecutor()
private var isRecording = false
private var camera: Camera? = null
private lateinit var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>
//onCreate
viewFinder = preview_video_view
runWithPermissions(*permissions) {
startCamera(view.context)
initClicks()
}
@SuppressLint("RestrictedApi", "UnsafeExperimentalUsageError")
private fun startCamera(context: Context) {
outputDirectory = getOutputDirectory(context)
cameraProviderFuture = ProcessCameraProvider.getInstance(context)
val cameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build()
// Create a configuration object for the video use case
val videoCaptureConfig = VideoCaptureConfig.Builder().apply {
setTargetRotation(viewFinder.display.rotation)
setCameraSelector(cameraSelector)
}
//CameraX.initialize(context, this.cameraXConfig)
videoCapture = VideoCapture(videoCaptureConfig.useCaseConfig)
val preview: Preview = Preview.Builder().apply {
setTargetAspectRatio(AspectRatio.RATIO_16_9)
setTargetRotation(viewFinder.display.rotation)
}.build()
preview.setSurfaceProvider(viewFinder.createSurfaceProvider())
cameraProviderFuture.addListener(Runnable {
val cameraProvider = cameraProviderFuture.get()
camera = cameraProvider.bindToLifecycle(
viewLifecycleOwner,
cameraSelector,
preview,
videoCapture
)
}, ContextCompat.getMainExecutor(context))
}
@SuppressLint("RestrictedApi")
private fun startRecording() {
val file = createFile(
outputDirectory,
FILENAME,
VIDEO_EXTENSION
)
videoCapture.startRecording(
file,
executor,
object : VideoCapture.OnVideoSavedCallback {
override fun onVideoSaved(file: File) {
Handler(Looper.getMainLooper()).post {
showMessage(file.name + " is saved")
}
}
override fun onError(videoCaptureError: Int, message: String, cause: Throwable?) {
Handler(Looper.getMainLooper()).post {
showMessage(videoCaptureError.toString() + " " + message)
}
}
}
)
}
@SuppressLint("RestrictedApi")
private fun stopRecording() {
videoCapture.stopRecording()
}
override fun getCameraXConfig(): CameraXConfig {
return Camera2Config.defaultConfig()
}
companion object {
private const val FILENAME = "yyyy_MM_dd_HH_mm_ss"
private const val VIDEO_EXTENSION = ".mp4"
private val permissions = arrayOf(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.CAMERA,
Manifest.permission.RECORD_AUDIO
)
fun getOutputDirectory(context: Context): File {
val appContext = context.applicationContext
val mediaDir = appContext.externalMediaDirs.firstOrNull()?.let {
File(it, appContext.resources.getString(R.string.app_name)).apply { mkdirs() }
}
return if (mediaDir != null && mediaDir.exists()) mediaDir else appContext.filesDir
}
fun createFile(baseFolder: File, format: String, extension: String) =
File(baseFolder, SimpleDateFormat(format, Locale.US)
.format(System.currentTimeMillis()) + extension)
}
val videoCapture = VideoCapture.Builder().build()
val outputDirectory = getOutputDirectory()
fun getOutputDirectory(): File {
val mediaDir = externalMediaDirs.firstOrNull()?.let {
File(it, resources.getString(R.string.app_name)).apply { mkdirs() } }
return if (mediaDir != null && mediaDir.exists())
mediaDir else filesDir
}
@SuppressLint("RestrictedApi")
private fun startRecording() {
val videoFile = File(
outputDirectory,
SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS", Locale.US
).format(System.currentTimeMillis()) + ".mp4")
val outputOptions = VideoCapture.OutputFileOptions.Builder(videoFile).build()
videoCapture?.startRecording(outputOptions, ContextCompat.getMainExecutor(this), object: VideoCapture.OnVideoSavedCallback {
override fun onError(videoCaptureError: Int, message: String, cause: Throwable?) {
Log.e(TAG, "Video capture failed: $message")
}
override fun onVideoSaved(outputFileResults: VideoCapture.OutputFileResults) {
val savedUri = Uri.fromFile(videoFile)
val msg = "Video capture succeeded: $savedUri"
Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
Log.d(TAG, msg)
}
})
}
@SuppressLint("RestrictedApi")
private fun stopRecording() {
videoCapture?.stopRecording()
}
videoCapture.startRecording(
VideoCapture.OutputFileOptions.Builder(file).build(),
executor,
object : VideoCapture.OnVideoSavedCallback {
override fun onVideoSaved(outputFileResults: VideoCapture.OutputFileResults) {
TODO("Not yet implemented")
}
override fun onError(videoCaptureError: Int, message: String, cause: Throwable?) {
TODO("Not yet implemented")
}
}
RECORD_AUDIO
权限。 - Sergey Stasishin