android - 使用并行协程工作程序运行 MediaMetadataRetriever getFrameAtIndex() 比使用一个协程运行慢
问题描述
我正在尝试使用MediaMetadataRetriever
多个并行协程作业从视频文件中抓取帧,但与使用一个协程运行它相比,该过程需要更多时间。
我不明白问题出在哪里,可能MediaMetadataRetriever
不适用于并行执行并且它会阻止getFrameAtIndex
同一文件的方法调用?或者问题出在并行文件访问中?
我的目标是尽快从约 1 秒的视频文件中检索所有位图,这就是我决定并行抓取帧的原因。
这是具有并行和一个协程执行的时间日志。
与一个协程
LOG_TAG: frame range 0..51 calculation for job_1 = 2206 ms
LOG_TAG_FINISHED: total grab time 2224
带有 4 个并行协程
LOG_TAG: frame range 39..51 calculation for job_4 = 4484 ms
LOG_TAG: frame range 0..12 calculation for job_1 = 4524 ms
LOG_TAG: frame range 27..39 calculation for job_3 = 4634 ms
LOG_TAG: frame range 12..27 calculation for job_2 = 4716 ms
LOG_TAG_FINISHED: total grab time 4747
和代码
suspend fun startGrabbingFrames(src: String){
val dataRetriever = MediaMetadataRetriever()
dataRetriever.setDataSource(src)
val totalFrames =
dataRetriever.extractMetadata(METADATA_KEY_VIDEO_FRAME_COUNT)?.toLongOrNull() ?: 0L
dataRetriever.release()
val frameChunkSize = totalFrames / 4
val offset1 = totalFrames - frameChunkSize * 2
val offset2 = totalFrames - frameChunkSize
val range1 = IntRange(0, frameChunkSize.toInt())
val range2 = IntRange(frameChunkSize.toInt(), offset1.toInt())
val range3 = IntRange(offset1.toInt(), offset2.toInt())
val range4 = IntRange(offset2.toInt(), totalFrames.toInt()-1)
val time = measureTimeMillis {
val one = CoroutineScope(Dispatchers.Default).async { grabFrames(src,range1,"job_1") }
val two = CoroutineScope(Dispatchers.Default).async { grabFrames(src, range2,"job_2") }
val three = CoroutineScope(Dispatchers.Default).async { grabFrames(src, range3,"job_3") }
val four = CoroutineScope(Dispatchers.Default).async { grabFrames(src, range4,"job_4") }
val frames1 = one.await()
val frames2 = two.await()
val frames3 = three.await()
val frames4 = four.await()
}
println("LOG_TAG_FINISHED: total grab time $time")
}
这是grabFrames
方法
private suspend fun grabFrames(src: String, range: IntRange, tag: String) = withContext(Dispatchers.Default) {
val retriever = MediaMetadataRetriever()
retriever.setDataSource(src)
val frames = ArrayList<Bitmap?>()
measureTimeMillis {
for (i in range) {
val frame = retriever.getFrameAtIndex(i)
frames.add(frame)
}
retriever.release()
}.also {
Log.d("LOG_TAG", "frame range $range calculation for $tag = ${it} ms")
}
frames
}
如果我只用一个协程运行它,它几乎快 2 倍,如日志所示。
val one = CoroutineScope(Dispatchers.Default).async { grabFrames(src,IntRange(0,totalFrames-1),"job_1") }
val fullFrames = one.await()
还尝试制作该文件的 4 个副本并MediaMetadataRetriever
为每个文件创建 4 个对象并运行 4 个并行作业,但结果是相同的。
解决方案
推荐阅读
- excel - 基于多列的条件累积和
- c++ - 信号/插槽 Qt5 C++
- .htaccess - 如果从 http 重定向到 https 已打开,则 pinterest 保存按钮不起作用
- html - 为什么我不能居中这个表格?
- dart - 错误“类型'未来
' 不是 'StreamTransformer 类型的子类型 - , 列表
>'" - c - 如何在这里使用 fscanf 从文件中写入变量?
- python - GBM生存的难以置信的可变重要性:重要性的恒定差异
- .net - XUnit - InvalidOperationException:无法使用应用程序根定位解决方案根
- r - 在运行 Shiny App 时修改非反应式 R 数据框
- python - AttributeError:“hyperopt_estimator”对象没有属性“_best_preprocs”