我正在开发一个需要将屏幕捕获为位图以进行传输的应用程序。我正在尝试使用新的 Android 5.0android.media.projection API进行屏幕捕获。
此 API 的工作流程最终会调用
mediaProjection.createVirtualDisplay("Test Screen", WIDTH, HEIGHT, DPI,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, surface, null, null);
在我最初尝试进行此捕获时,我从 SurfaceView 获取了表面对象。这可以正常工作;最终结果是在屏幕上绘制的显示的微小副本(导致德罗斯特效应)
我以为这个功能已经快完成了,但是然后我发现SurfaceView(从代码的角度来看)不可读;你不能从他们那里得到位图。
在寻找其他解决方案时我遇到了这个问题它与我的目标非常相似,在该线程中它是建议使用 ImageReader 而不是 SurfaceView 来获取传递给 createVirtualDisplay API 调用的 Surface。
但是,当我更改代码以使用 ImageReader 代替 SurfaceView 时,我会收到运行时 logcat 错误(无例外),并且 ImageReader 的回调函数永远不会被调用。 createVirtualDisplay 调用还返回一个看似有效的 VirtualDisplay 对象。
这是日志猫:
9230-9270/com.android.techrocket9.nanoid E/BufferQueueProducer﹕ [unnamed-9230-0] dequeueBuffer: createGraphicBuffer failed
9230-9246/com.android.techrocket9.nanoid E/BufferQueueProducer﹕ [unnamed-9230-0] dequeueBuffer: can't dequeue multiple buffers without setting the buffer count
9230-9246/com.android.techrocket9.nanoid E/BufferQueueProducer﹕ [unnamed-9230-0] dequeueBuffer: can't dequeue multiple buffers without setting the buffer count
9230-9246/com.android.techrocket9.nanoid E/BufferQueueProducer﹕ [unnamed-9230-0] dequeueBuffer: can't dequeue multiple buffers without setting the buffer count
9230-9246/com.android.techrocket9.nanoid E/BufferQueueProducer﹕ [unnamed-9230-0] dequeueBuffer: can't dequeue multiple buffers without setting the buffer count
第二行在停止出现之前会重复大约 100 次。
在调试器上单步调试,我发现第一个错误发生在 createVirtualDisplay 调用期间,而所有其他错误都发生在执行返回到系统代码之后的某个时刻。
The 唯一有意义的结果此错误与 Kitkat 中的一个问题有关,其中我尝试使用的 API 不存在。尽管如此,我尝试了此处建议修复(推杆android:hardwareAccelerated="false"
在清单中)。这并没有改变应用程序的行为。
如何“设置缓冲区计数”或以其他方式解决此错误并将屏幕显示为位图?
附:我的开发平台是 Nexus 6。
根据要求,完整的代码块:
MediaProjection mediaProjection = mgr.getMediaProjection(resultCode, data);
ImageReader ir = ImageReader.newInstance(WIDTH, HEIGHT, ImageFormat.JPEG, 5);
VirtualDisplay v = mediaProjection.createVirtualDisplay("Test Screen", WIDTH, HEIGHT, getApplicationContext().getResources().getDisplayMetrics().densityDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, ir.getSurface(), null, null);
编辑:关于伪影问题,这是我用来从图像中获取位图并显示它的代码:
public void onImageAvailable(ImageReader reader) {
Image image = null;
ByteArrayOutputStream bos = null;
try {
image = reader.acquireLatestImage();
if (null == image){
return;
}
bos = new ByteArrayOutputStream();
final Image.Plane[] planes = image.getPlanes();
final ByteBuffer buffer = (ByteBuffer) planes[0].getBuffer().rewind();
final Bitmap bitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);
bitmap.copyPixelsFromBuffer(buffer);
//bitmap.compress(Bitmap.CompressFormat.WEBP, 50, bos);
runOnUiThread(new Runnable() {
public void run() {
iv.setImageBitmap(bitmap);
}
});