arm*_*ani 5 android video-capture kotlin
我正在尝试将旧手机变成联网的安全摄像头,因为在所有这些骚乱期间,我所在地区的犯罪率急剧增加(而且我不想依赖其他人的应用程序来控制对我私人时刻的访问)。
我正在分块发送,所以摄像机会记录视频几秒钟,然后停止,将捕获的文件的二进制文件编码为 Base64,然后通过 POST 请求将其发送到家庭服务器,所有这些都是无限循环的。服务器解包 + 解码 + 将其作为原始二进制“MP4”保存到自己的磁盘上(TODO:运动检测的有趣后处理)。
在(和周围)我的目标手机的操作系统版本和屏幕尺寸上使用各种虚拟设备,这一切都可以长时间工作。我已经使用 60 秒的块超过 15 分钟,加上 6 秒的块超过一个小时。我一直收到模拟器在我的服务器上生成的愚蠢的虚拟房间视频。
但是在运行 Android 6.0.1 并梦想成为安全摄像头的三星 Galaxy S5 上,通常需要发送 2 到 3 个视频,然后应用程序才会崩溃……除非您将分辨率设置得太高,然后您会遇到不同的症状。
E/Parcel:dup() 在 Parcel::read 中失败,i 为 1,fds[i] 为 -1,fd_count 为 2,错误:打开的文件太多
E/Surface:dequeueBuffer:IGraphicBufferProducer::requestBuffer 失败:-22
W/Adreno-EGLSUB: DequeueBuffer:721: dequeue native buffer failure: Invalid argument, buffer=0x0, handle=0x0
W/Adreno-EGL: <qeglDrvAPI_eglSwapBuffers:3800>: EGL_BAD_SURFACE
紧随其后的是第二个错误:
E/CameraDeviceGLThread-1:在 GL 渲染线程上收到异常:
Run Code Online (Sandbox Code Playgroud)java.lang.IllegalStateException: swapBuffers: EGL error: 0x300d
最后,一旦块时间到了,相机再次开始录制,就会发生最终错误,使整个应用程序崩溃:
I/CameraDeviceState:传统相机服务转换到状态 ERROR
E/AndroidRuntime:致命异常:CameraThread
Run Code Online (Sandbox Code Playgroud)Process: com.example.roselawncam, PID: 14639android.hardware.camera2.CameraAccessException: 相机设备遇到严重错误
这些警告清楚地表明资源紧张会导致此症状。它们发生在应用程序崩溃时,更高的分辨率会导致更快的崩溃。我给这些坏男孩计时:
前置和后置摄像头的时间相似。在较低的分辨率下,除非您增加块时间,否则您会开始遇到症状 #0。反正:
W/Adreno-GSL:<gsl_ldd_control:475>:ioctl fd 28 代码 0xc01c0915 (IOCTL_KGSL_MAP_USER_MEM) 失败:errno 12内存不足
W/Adreno-EGLSUB: SyncBackBuffer:3130:无法为 fd=281 offs=0 映射内存
E/Adreno-EGLSUB:SyncBackBuffer:3131:SyncBackBuffer:致命错误:(空)
A/Adreno-GSL:从函数 SyncBackBuffer 和第 3131 行退出进程 com.example.roselawncam
A/libc:致命信号 6 (SIGABRT),tid 19618 中的代码 -6 (CameraDeviceGLT)
最后,相关的 Kotlin 片段:
private fun createRecorder(surface: Surface) = MediaRecorder().apply {
setAudioSource(MediaRecorder.AudioSource.MIC)
setVideoSource(MediaRecorder.VideoSource.SURFACE)
setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
setOutputFile(outputFile.absolutePath)
setVideoEncodingBitRate(RECORDER_VIDEO_BITRATE)
if (args_fps > 0) setVideoFrameRate(args_fps)
setVideoSize(args_width, args_height)
setVideoEncoder(MediaRecorder.VideoEncoder.H264)
setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
setInputSurface(surface)
}
private fun recordIt(cameraManager: CameraManager, cameraThread: HandlerThread) {
val cameraHandler = Handler(cameraThread.looper)
val stateCallback: CameraDevice.StateCallback = object: CameraDevice.StateCallback() {
override fun onOpened(camera: CameraDevice) {
camera.createCaptureSession(
listOf<Surface>(recorderSurface),
object : CameraCaptureSession.StateCallback() {
override fun onConfigured(session: CameraCaptureSession) {
val recTimeSeconds = findViewById<TextView>(R.id.recTimeSeconds)
val chunkTimeMilliseconds = recTimeSeconds.text.toString().toLong() * 1000
// Boolean "stopREC" (e.g. "Stop Recording") is false at this point
while (!stopREC) {
// // // This loop should run forever, but crashes after a few times // // //
val recorder: MediaRecorder by lazy { createRecorder(recorderSurface) }
val recordRequest: CaptureRequest by lazy {
session.device.createCaptureRequest(CameraDevice.TEMPLATE_RECORD).apply {
addTarget(recorderSurface)
set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, Range(args_fps, args_fps))
}.build()
}
session.setRepeatingRequest(recordRequest, null, cameraHandler)
recorder.apply { prepare(); start() }
Thread.sleep(chunkTimeMilliseconds)
recorder.apply { stop(); release() }
// Send the video file across the network in JSON via POST request:
val params = HashMap<String, String>()
params["videodata"] = convertToBase64(outputFile)
val jsonObject = JSONObject(params as Map<*, *>)
val request = JsonObjectRequest(Request.Method.POST, url, jsonObject, null, null)
queue.add(request)
// // // End of loop that should've ran forever, but crashes occasionally instead // // //
}
camera.close()
}
override fun onConfigureFailed(session: CameraCaptureSession) {}
},
cameraHandler
)
}
override fun onDisconnected(camera: CameraDevice) { recorder.stop(); recorder.release() }
override fun onError(camera: CameraDevice, error:Int) { camera.close() }
}
cameraManager.openCamera(args_cameraId, stateCallback, cameraHandler)
}
Run Code Online (Sandbox Code Playgroud)
我有一些建议:
在需要的地方强制使用同步函数,file lock以便线程按顺序执行该代码块,file stream以有组织的方式打开和关闭,例如,访问文件。这样就可以避免out of memory错误file already in use。
是否可以不将文件编码为Base 64?字符串太大,检查是否避免出现任何错误。
以及制作自己的应用程序的好倡议。
| 归档时间: |
|
| 查看次数: |
492 次 |
| 最近记录: |