问题描述
是否可以将安卓相机的视频直接录制为 MJPEG?出于质量目的,我对 MJPEG 感兴趣。我不想通过默认的 android 设置录制视频然后转换为 MJPEG,而是直接从相机设备转换为 MJPEG。这可能吗?我找不到任何信息表明这是可能的。
解决方法
Kotlin 中的代码。
您只需要通过 setRepeatingRequest 获取捕获请求上的连续图像。 调用 takeMJPEG,true 开始,false 停止。
用 GOM 播放器打开生成的文件。我已经测试了实现。
private val takeMJPEGSemaphore = Semaphore(1)
var mjpegBufferStream: BufferedOutputStream? = null
var mjpegFileStream: FileOutputStream? = null
var mjpegRecording = false
override fun takeMJPEG(start: Boolean) {
Log.i(TAG,"takeMJPEG start:$start")
if (start) {
takeMJPEGSemaphore.acquire()
mjpegRecording = true
val mjpegOutputFile = createFile(context,"mjpeg")
mjpegFileStream = FileOutputStream(mjpegOutputFile)
mjpegBufferStream = BufferedOutputStream(mjpegFileStream)
// Clear imageReader
var image: Image? = null
do {
image?.close()
image = imageReader.acquireNextImage()
} while (image != null)
session.stopRepeating()
session.setRepeatingRequest(captureRequest.build(),null,cameraHandler)
var count = 0
var initialTime: Long = 0
imageReader.setOnImageAvailableListener({ reader ->
image = reader.acquireNextImage()
if (count == 0) {
initialTime = image!!.timestamp
}
count++
val buffer = image?.planes?.get(0)?.buffer
val bytes = ByteArray(buffer!!.remaining()).apply { buffer.get(this) }
mjpegBufferStream!!.write(bytes)
mjpegBufferStream!!.flush()
if (!mjpegRecording) {
imageReader.setOnImageAvailableListener(null,null)
session.stopRepeating()
session.setRepeatingRequest(previewRequest.build(),cameraHandler)
// Save the mjpeg file
mjpegBufferStream?.flush()
mjpegBufferStream?.close()
val finalTime = image!!.timestamp
Log.i(TAG,"saved mjpeg file with fps = ${count / ((finalTime - initialTime) / 1000000000.0)}")
takeMJPEGSemaphore.release()
}
image?.close()
},imageReaderHandler)
} else {
mjpegRecording = false
takeMJPEGSemaphore.acquire()
takeMJPEGSemaphore.release()
}
}
private fun createFile(context: Context,extension: String): File {
val dir = File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DCIM),"Camera")
if (!dir.exists()) {
dir.mkdirs()
}
return File.createTempFile(createFileName(),".$extension",dir)
}
private fun createFileName(): String {
val sdf = SimpleDateFormat("yyyy_MM_dd_HH_mm_ss_SSS",Locale.US)
return "IMG_${sdf.format(Date())}"
}